Search Unity

Restrict TextField input

Discussion in 'UI Toolkit' started by ErnestSurys, Sep 7, 2019.

  1. ErnestSurys

    ErnestSurys

    Joined:
    Jan 18, 2018
    Posts:
    94
    Hi,
    I want to make a `FileNameTextField` or `FileNameManipulator` that restrict input so that user can only enter a file name friendly string.

    My first try was to simply make a manipulator and stopping KeyDown event propagation if the character was invalid. That simply didn't affect TextField value.

    The second attempt looked like this:

    Code (CSharp):
    1.  
    2.     public class FileNameField : TextValueField<string>
    3.     {
    4.         public FileNameField(): base(null, -1, new FileNameInput())
    5.         {
    6.         }
    7.  
    8.         public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, string startValue)
    9.         {
    10.         }
    11.  
    12.         protected override string StringToValue(string str) => str;
    13.  
    14.         protected override string ValueToString(string value) => value;
    15.  
    16.         class FileNameInput : TextValueInput
    17.         {
    18.             protected override string allowedCharacters => "test";
    19.  
    20.             public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, string startValue)
    21.             {
    22.                
    23.             }
    24.  
    25.             protected override string ValueToString(string value) => value;
    26.         }
    27.     }

    It did filter the characters but started to throw `NotSupportedException: Specified method is not supported` every time I typed character. Also, I think that doing this by manipulator would be a much cleaner approach.

    So, what is the proper way to do this?
     
  2. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    Can you post the full stack trace? It's hard to know what could be wrong.
     
  3. ErnestSurys

    ErnestSurys

    Joined:
    Jan 18, 2018
    Posts:
    94
    This is it:
    NotSupportedException: Specified method is not supported.
    UnityEngine.UIElements.TextInputBaseField`1+TextInputBase[TValueType].StringToValue (System.String str) (at /Users/builduser/buildslave/unity/build/Modules/UIElements/Controls/TextInputFieldBase.cs:242)
    UnityEditor.UIElements.TextValueField`1+TextValueInput[TValueType].StringToValue (System.String str) (at /Users/builduser/buildslave/unity/build/Editor/Mono/UIElements/Controls/TextValueField.cs:133)
    UnityEngine.UIElements.TextInputBaseField`1+TextInputBase[TValueType].UpdateValueFromText () (at /Users/builduser/buildslave/unity/build/Modules/UIElements/Controls/TextInputFieldBase.cs:247)
    UnityEditor.UIElements.TextValueField`1+TextValueInput[TValueType].ExecuteDefaultActionAtTarget (UnityEngine.UIElements.EventBase evt) (at /Users/builduser/buildslave/unity/build/Editor/Mono/UIElements/Controls/TextValueField.cs:173)
    UnityEngine.UIElements.CallbackEventHandler.HandleEvent (UnityEngine.UIElements.EventBase evt) (at /Users/builduser/buildslave/unity/build/Modules/UIElements/Events/EventHandler.cs:106)
    UnityEngine.UIElements.EventDispatchUtilities.PropagateEvent (UnityEngine.UIElements.EventBase evt) (at /Users/builduser/buildslave/unity/build/Modules/UIElements/Events/IEventDispatchingStrategy.cs:95)
    UnityEngine.UIElements.KeyboardEventDispatchingStrategy.DispatchEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at /Users/builduser/buildslave/unity/build/Modules/UIElements/Events/KeyboardEventDispatchingStrategy.cs:30)
    UnityEngine.UIElements.EventDispatcher.ProcessEvent (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel) (at /Users/builduser/buildslave/unity/build/Modules/UIElements/EventDispatcher.cs:277)
    UnityEngine.UIElements.EventDispatcher.Dispatch (UnityEngine.UIElements.EventBase evt, UnityEngine.UIElements.IPanel panel, UnityEngine.UIElements.DispatchMode dispatchMode) (at /Users/builduser/buildslave/unity/build/Modules/UIElements/EventDispatcher.cs:159)
    UnityEngine.UIElements.BaseVisualElementPanel.SendEvent (UnityEngine.UIElements.EventBase e, UnityEngine.UIElements.DispatchMode dispatchMode) (at /Users/builduser/buildslave/unity/build/Modules/UIElements/Panel.cs:245)
    UnityEngine.UIElements.UIElementsUtility.DoDispatch (UnityEngine.UIElements.BaseVisualElementPanel panel) (at /Users/builduser/buildslave/unity/build/Modules/UIElements/UIElementsUtility.bindings.cs:359)
    UnityEngine.UIElements.UIElementsUtility.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr) (at /Users/builduser/buildslave/unity/build/Modules/UIElements/UIElementsUtility.bindings.cs:154)
    UnityEngine.GUIUtility.ProcessEvent (System.Int32 instanceID, System.IntPtr nativeEventPtr) (at /Users/builduser/buildslave/unity/build/Modules/IMGUI/GUIUtility.cs:179)
     
  4. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    It looks like you need to override StringToValue for the FileNameInput class as well.
     
  5. ErnestSurys

    ErnestSurys

    Joined:
    Jan 18, 2018
    Posts:
    94
    Thanks Jonathan,
    I was hoping for someone to hint a solution that doesn't depends on
    TextValueField
    but for now this works.
    For anyone interested this is the working snippet:

    Code (CSharp):
    1.     public class FileNameField : TextValueField<string>
    2.     {
    3.         public FileNameField() : base(null, -1, new FileNameInput()) { }
    4.  
    5.         public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, string startValue) { }
    6.  
    7.         protected override string StringToValue(string str) => str;
    8.  
    9.         protected override string ValueToString(string value) => value;
    10.  
    11.         class FileNameInput : TextValueInput
    12.         {
    13.             private readonly string _allowedChars;
    14.  
    15.             protected override string allowedCharacters => _allowedChars;
    16.  
    17.             public FileNameInput()
    18.             {
    19.                 _allowedChars = new string(Enumerable.Range(char.MinValue, char.MaxValue)
    20.                     .Select(c => (char)c)
    21.                     .Where(c => !char.IsControl(c))
    22.                     .Except(Path.GetInvalidFileNameChars())
    23.                     .ToArray());
    24.             }
    25.  
    26.             public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, string startValue) { }
    27.  
    28.             protected override string ValueToString(string value) => value;
    29.  
    30.             protected override string StringToValue(string str) => str;
    31.         }
    32.     }