[NUI] Add SelectionStarted event (#3912)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / BaseComponents / TextFieldEvent.cs
index c8b8bbf..fc8b5a7 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright(c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
  */
 
 using System;
+using System.ComponentModel;
 using System.Runtime.InteropServices;
 
 namespace Tizen.NUI.BaseComponents
@@ -26,17 +27,52 @@ namespace Tizen.NUI.BaseComponents
     /// <since_tizen> 3 </since_tizen>
     public partial class TextField
     {
-        private EventHandler<TextChangedEventArgs> _textFieldTextChangedEventHandler;
-        private TextChangedCallbackDelegate _textFieldTextChangedCallbackDelegate;
-        private EventHandler<MaxLengthReachedEventArgs> _textFieldMaxLengthReachedEventHandler;
-        private MaxLengthReachedCallbackDelegate _textFieldMaxLengthReachedCallbackDelegate;
+        private EventHandler<TextChangedEventArgs> textFieldTextChangedEventHandler;
+        private TextChangedCallbackDelegate textFieldTextChangedCallbackDelegate;
+        private EventHandler textFieldCursorPositionChangedEventHandler;
+        private CursorPositionChangedCallbackDelegate textFieldCursorPositionChangedCallbackDelegate;
+        private EventHandler<MaxLengthReachedEventArgs> textFieldMaxLengthReachedEventHandler;
+        private MaxLengthReachedCallbackDelegate textFieldMaxLengthReachedCallbackDelegate;
+        private EventHandler<AnchorClickedEventArgs> textFieldAnchorClickedEventHandler;
+        private AnchorClickedCallbackDelegate textFieldAnchorClickedCallbackDelegate;
+
+        private EventHandler textFieldSelectionChangedEventHandler;
+        private SelectionChangedCallbackDelegate textFieldSelectionChangedCallbackDelegate;
+
+        private EventHandler<InputFilteredEventArgs> textFieldInputFilteredEventHandler;
+        private InputFilteredCallbackDelegate textFieldInputFilteredCallbackDelegate;
+        private EventHandler textFieldSelectionClearedEventHandler;
+        private SelectionClearedCallbackDelegate textFieldSelectionClearedCallbackDelegate;
+
+        private EventHandler textFieldSelectionStartedEventHandler;
+        private SelectionStartedCallbackDelegate textFieldSelectionStartedCallbackDelegate;
 
         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
         private delegate void TextChangedCallbackDelegate(IntPtr textField);
 
         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate void CursorPositionChangedCallbackDelegate(IntPtr textField, uint oldPosition);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
         private delegate void MaxLengthReachedCallbackDelegate(IntPtr textField);
 
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate void AnchorClickedCallbackDelegate(IntPtr textField, IntPtr href, uint hrefLength);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate void SelectionChangedCallbackDelegate(IntPtr textField, uint oldStart, uint oldEnd);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate void InputFilteredCallbackDelegate(IntPtr textField, InputFilterType type);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate void SelectionClearedCallbackDelegate(IntPtr textField);
+
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        private delegate void SelectionStartedCallbackDelegate(IntPtr textField);
+
+        private bool invokeTextChanged = true;
+
         /// <summary>
         /// The TextChanged event.
         /// </summary>
@@ -45,20 +81,45 @@ namespace Tizen.NUI.BaseComponents
         {
             add
             {
-                if (_textFieldTextChangedEventHandler == null)
+                if (textFieldTextChangedEventHandler == null)
+                {
+                    textFieldTextChangedCallbackDelegate = (OnTextChanged);
+                    TextChangedSignal().Connect(textFieldTextChangedCallbackDelegate);
+                }
+                textFieldTextChangedEventHandler += value;
+            }
+            remove
+            {
+                textFieldTextChangedEventHandler -= value;
+                if (textFieldTextChangedEventHandler == null && TextChangedSignal().Empty() == false)
+                {
+                    TextChangedSignal().Disconnect(textFieldTextChangedCallbackDelegate);
+                }
+            }
+        }
+
+        /// <summary>
+        /// The CursorPositionChanged event is emitted whenever the primary cursor position changed.
+        /// </summary>
+        /// <since_tizen> 9 </since_tizen>
+        public event EventHandler CursorPositionChanged
+        {
+            add
+            {
+                if (textFieldCursorPositionChangedEventHandler == null)
                 {
-                    _textFieldTextChangedCallbackDelegate = (OnTextChanged);
-                    TextChangedSignal().Connect(_textFieldTextChangedCallbackDelegate);
+                    textFieldCursorPositionChangedCallbackDelegate = (OnCursorPositionChanged);
+                    CursorPositionChangedSignal().Connect(textFieldCursorPositionChangedCallbackDelegate);
                 }
-                _textFieldTextChangedEventHandler += value;
+                textFieldCursorPositionChangedEventHandler += value;
             }
             remove
             {
-                _textFieldTextChangedEventHandler -= value;
-                if (_textFieldTextChangedEventHandler == null && TextChangedSignal().Empty() == false)
+                if (textFieldCursorPositionChangedEventHandler == null && CursorPositionChangedSignal().Empty() == false)
                 {
-                    TextChangedSignal().Disconnect(_textFieldTextChangedCallbackDelegate);
+                    this.CursorPositionChangedSignal().Disconnect(textFieldCursorPositionChangedCallbackDelegate);
                 }
+                textFieldCursorPositionChangedEventHandler -= value;
             }
         }
 
@@ -70,72 +131,303 @@ namespace Tizen.NUI.BaseComponents
         {
             add
             {
-                if (_textFieldMaxLengthReachedEventHandler == null)
+                if (textFieldMaxLengthReachedEventHandler == null)
+                {
+                    textFieldMaxLengthReachedCallbackDelegate = (OnMaxLengthReached);
+                    MaxLengthReachedSignal().Connect(textFieldMaxLengthReachedCallbackDelegate);
+                }
+                textFieldMaxLengthReachedEventHandler += value;
+            }
+            remove
+            {
+                if (textFieldMaxLengthReachedEventHandler == null && MaxLengthReachedSignal().Empty() == false)
+                {
+                    this.MaxLengthReachedSignal().Disconnect(textFieldMaxLengthReachedCallbackDelegate);
+                }
+                textFieldMaxLengthReachedEventHandler -= value;
+            }
+        }
+
+        /// <summary>
+        /// The SelectionStarted event is emitted when the selection start.
+        /// </summary>
+        /// This will be public opened in after ACR done. Before ACR, need to be hidden as inhouse API.
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public event EventHandler SelectionStarted
+        {
+            add
+            {
+                if (textFieldSelectionStartedEventHandler == null)
+                {
+                    textFieldSelectionStartedCallbackDelegate = (OnSelectionStarted);
+                    SelectionStartedSignal().Connect(textFieldSelectionStartedCallbackDelegate);
+                }
+                textFieldSelectionStartedEventHandler += value;
+            }
+            remove
+            {
+                if (textFieldSelectionStartedEventHandler == null && SelectionStartedSignal().Empty() == false)
+                {
+                    this.SelectionStartedSignal().Disconnect(textFieldSelectionStartedCallbackDelegate);
+                }
+                textFieldSelectionStartedEventHandler -= value;
+            }
+        }
+
+        /// <summary>
+        /// The SelectionCleared signal is emitted when selection is cleared.
+        /// </summary>
+        /// <since_tizen> 9 </since_tizen>
+        public event EventHandler SelectionCleared
+        {
+            add
+            {
+                if (textFieldSelectionClearedEventHandler == null)
+                {
+                    textFieldSelectionClearedCallbackDelegate = (OnSelectionCleared);
+                    SelectionClearedSignal().Connect(textFieldSelectionClearedCallbackDelegate);
+                }
+                textFieldSelectionClearedEventHandler += value;
+            }
+            remove
+            {
+                if (textFieldSelectionClearedEventHandler == null && SelectionClearedSignal().Empty() == false)
+                {
+                    this.SelectionClearedSignal().Disconnect(textFieldSelectionClearedCallbackDelegate);
+                }
+                textFieldSelectionClearedEventHandler -= value;
+            }
+        }
+
+        /// <summary>
+        /// The AnchorClicked signal is emitted when the anchor is clicked.
+        /// </summary>
+        /// <since_tizen> 9 </since_tizen>
+        public event EventHandler<AnchorClickedEventArgs> AnchorClicked
+        {
+            add
+            {
+                if (textFieldAnchorClickedEventHandler == null)
+                {
+                    textFieldAnchorClickedCallbackDelegate = (OnAnchorClicked);
+                    AnchorClickedSignal().Connect(textFieldAnchorClickedCallbackDelegate);
+                }
+                textFieldAnchorClickedEventHandler += value;
+            }
+            remove
+            {
+                textFieldAnchorClickedEventHandler -= value;
+                if (textFieldAnchorClickedEventHandler == null && AnchorClickedSignal().Empty() == false)
+                {
+                    AnchorClickedSignal().Disconnect(textFieldAnchorClickedCallbackDelegate);
+                }
+            }
+        }
+
+        /// <summary>
+        /// The SelectionChanged event is emitted whenever the selected text is changed.
+        /// </summary>
+        /// <since_tizen> 9 </since_tizen>
+        public event EventHandler SelectionChanged
+        {
+            add
+            {
+                if (textFieldSelectionChangedEventHandler == null)
+                {
+                    textFieldSelectionChangedCallbackDelegate = (OnSelectionChanged);
+                    SelectionChangedSignal().Connect(textFieldSelectionChangedCallbackDelegate);
+                }
+                textFieldSelectionChangedEventHandler += value;
+            }
+            remove
+            {
+                if (textFieldSelectionChangedEventHandler == null && SelectionChangedSignal().Empty() == false)
+                {
+                    this.SelectionChangedSignal().Disconnect(textFieldSelectionChangedCallbackDelegate);
+                }
+                textFieldSelectionChangedEventHandler -= value;
+            }
+        }
+
+        /// <summary>
+        /// The InputFiltered signal is emitted when the input is filtered by InputFilter. <br />
+        /// </summary>
+        /// <remarks>
+        /// See <see cref="InputFilterType"/> and <see cref="InputFilteredEventArgs"/> for a detailed description. <br />
+        /// </remarks>
+        /// <example>
+        /// The following example demonstrates how to use the InputFiltered event.
+        /// <code>
+        /// field.InputFiltered += (s, e) =>
+        /// {
+        ///     if (e.Type == InputFilterType.Accept)
+        ///     {
+        ///         // If input is filtered by InputFilter of Accept type.
+        ///     }
+        ///     else if (e.Type == InputFilterType.Reject)
+        ///     {
+        ///         // If input is filtered by InputFilter of Reject type.
+        ///     }
+        /// };
+        /// </code>
+        /// </example>
+        /// <since_tizen> 9 </since_tizen>
+        public event EventHandler<InputFilteredEventArgs> InputFiltered
+        {
+            add
+            {
+                if (textFieldInputFilteredEventHandler == null)
                 {
-                    _textFieldMaxLengthReachedCallbackDelegate = (OnMaxLengthReached);
-                    MaxLengthReachedSignal().Connect(_textFieldMaxLengthReachedCallbackDelegate);
+                    textFieldInputFilteredCallbackDelegate = (OnInputFiltered);
+                    InputFilteredSignal().Connect(textFieldInputFilteredCallbackDelegate);
                 }
-                _textFieldMaxLengthReachedEventHandler += value;
+                textFieldInputFilteredEventHandler += value;
             }
             remove
             {
-                if (_textFieldMaxLengthReachedEventHandler == null && MaxLengthReachedSignal().Empty() == false)
+                textFieldInputFilteredEventHandler -= value;
+                if (textFieldInputFilteredEventHandler == null && InputFilteredSignal().Empty() == false)
                 {
-                    this.MaxLengthReachedSignal().Disconnect(_textFieldMaxLengthReachedCallbackDelegate);
+                    InputFilteredSignal().Disconnect(textFieldInputFilteredCallbackDelegate);
                 }
-                _textFieldMaxLengthReachedEventHandler -= value;
             }
         }
 
+        internal TextFieldSignal SelectionStartedSignal()
+        {
+            TextFieldSignal ret = new TextFieldSignal(Interop.TextField.SelectionStartedSignal(SwigCPtr), false);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
+        internal TextFieldSignal SelectionClearedSignal()
+        {
+            TextFieldSignal ret = new TextFieldSignal(Interop.TextField.SelectionClearedSignal(SwigCPtr), false);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
         internal TextFieldSignal TextChangedSignal()
         {
-            TextFieldSignal ret = new TextFieldSignal(Interop.TextField.TextField_TextChangedSignal(swigCPtr), false);
+            TextFieldSignal ret = new TextFieldSignal(Interop.TextField.TextChangedSignal(SwigCPtr), false);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
+        internal TextFieldSignal CursorPositionChangedSignal()
+        {
+            TextFieldSignal ret = new TextFieldSignal(Interop.TextField.CursorPositionChangedSignal(SwigCPtr), false);
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
             return ret;
         }
 
         internal TextFieldSignal MaxLengthReachedSignal()
         {
-            TextFieldSignal ret = new TextFieldSignal(Interop.TextField.TextField_MaxLengthReachedSignal(swigCPtr), false);
+            TextFieldSignal ret = new TextFieldSignal(Interop.TextField.MaxLengthReachedSignal(SwigCPtr), false);
             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
             return ret;
         }
 
-        private void OnTextChanged(IntPtr textField)
+        internal TextFieldSignal AnchorClickedSignal()
+        {
+            TextFieldSignal ret = new TextFieldSignal(Interop.TextField.AnchorClickedSignal(SwigCPtr), false);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
+        internal TextFieldSignal SelectionChangedSignal()
+        {
+            TextFieldSignal ret = new TextFieldSignal(Interop.TextField.SelectionChangedSignal(SwigCPtr), false);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
+        internal TextFieldSignal InputFilteredSignal()
+        {
+            TextFieldSignal ret = new TextFieldSignal(Interop.TextField.InputFilteredSignal(SwigCPtr), false);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return ret;
+        }
+
+        private void OnSelectionStarted(IntPtr textField)
         {
-            TextChangedEventArgs e = new TextChangedEventArgs();
+            //no data to be sent to the user
+            textFieldSelectionStartedEventHandler?.Invoke(this, EventArgs.Empty);
+        }
 
-            // Populate all members of "e" (TextChangedEventArgs) with real data
-            e.TextField = Registry.GetManagedBaseHandleFromNativePtr(textField) as TextField;
+        private void OnSelectionCleared(IntPtr textField)
+        {
+            //no data to be sent to the user
+            textFieldSelectionClearedEventHandler?.Invoke(this, EventArgs.Empty);
+        }
 
-            if (_textFieldTextChangedEventHandler != null)
+        private void OnTextChanged(IntPtr textField)
+        {
+            if (textFieldTextChangedEventHandler != null && invokeTextChanged)
             {
+                TextChangedEventArgs e = new TextChangedEventArgs();
+
+                // Populate all members of "e" (TextChangedEventArgs) with real data
+                e.TextField = Registry.GetManagedBaseHandleFromNativePtr(textField) as TextField;
                 //here we send all data to user event handlers
-                _textFieldTextChangedEventHandler(this, e);
+                textFieldTextChangedEventHandler(this, e);
             }
         }
 
-        private void OnMaxLengthReached(IntPtr textField)
+        private void OnCursorPositionChanged(IntPtr textField, uint oldPosition)
         {
-            MaxLengthReachedEventArgs e = new MaxLengthReachedEventArgs();
-
-            // Populate all members of "e" (MaxLengthReachedEventArgs) with real data
-            e.TextField = Registry.GetManagedBaseHandleFromNativePtr(textField) as TextField;
+            // no data to be sent to the user, as in NUI there is no event provide old values.
+            textFieldCursorPositionChangedEventHandler?.Invoke(this, EventArgs.Empty);
+        }
 
-            if (_textFieldMaxLengthReachedEventHandler != null)
+        private void OnMaxLengthReached(IntPtr textField)
+        {
+            if (textFieldMaxLengthReachedEventHandler != null)
             {
+                MaxLengthReachedEventArgs e = new MaxLengthReachedEventArgs();
+
+                // Populate all members of "e" (MaxLengthReachedEventArgs) with real data
+                e.TextField = Registry.GetManagedBaseHandleFromNativePtr(textField) as TextField;
                 //here we send all data to user event handlers
-                _textFieldMaxLengthReachedEventHandler(this, e);
+                textFieldMaxLengthReachedEventHandler(this, e);
             }
         }
 
+        private void OnAnchorClicked(IntPtr textField, IntPtr href, uint hrefLength)
+        {
+            // Note: hrefLength is useful for get the length of a const char* (href) in dali-toolkit.
+            // But NUI can get the length of string (href), so hrefLength is not necessary in NUI.
+            AnchorClickedEventArgs e = new AnchorClickedEventArgs();
+
+            // Populate all members of "e" (AnchorClickedEventArgs) with real data
+            e.Href = Marshal.PtrToStringAnsi(href);
+            //here we send all data to user event handlers
+            textFieldAnchorClickedEventHandler?.Invoke(this, e);
+        }
+
+        private void OnSelectionChanged(IntPtr textField, uint oldStart, uint oldEnd)
+        {
+            // no data to be sent to the user, as in NUI there is no event provide old values.
+            textFieldSelectionChangedEventHandler?.Invoke(this, EventArgs.Empty);
+        }
+
+        private void OnInputFiltered(IntPtr textField, InputFilterType type)
+        {
+            InputFilteredEventArgs e = new InputFilteredEventArgs();
+
+            // Populate all members of "e" (InputFilteredEventArgs) with real data
+            e.Type = type;
+            //here we send all data to user event handlers
+            textFieldInputFilteredEventHandler?.Invoke(this, e);
+        }
+
         /// <summary>
         /// The TextChanged event arguments.
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
         public class TextChangedEventArgs : EventArgs
         {
-            private TextField _textField;
+            private TextField textField;
 
             /// <summary>
             /// TextField.
@@ -145,11 +437,11 @@ namespace Tizen.NUI.BaseComponents
             {
                 get
                 {
-                    return _textField;
+                    return textField;
                 }
                 set
                 {
-                    _textField = value;
+                    textField = value;
                 }
             }
         }
@@ -160,7 +452,7 @@ namespace Tizen.NUI.BaseComponents
         /// <since_tizen> 3 </since_tizen>
         public class MaxLengthReachedEventArgs : EventArgs
         {
-            private TextField _textField;
+            private TextField textField;
 
             /// <summary>
             /// TextField.
@@ -170,11 +462,11 @@ namespace Tizen.NUI.BaseComponents
             {
                 get
                 {
-                    return _textField;
+                    return textField;
                 }
                 set
                 {
-                    _textField = value;
+                    textField = value;
                 }
             }
         }