[NUI] Make SelectionChanged event for TextField & TextEditor public
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / BaseComponents / TextFieldEvent.cs
1 /*
2  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System;
19 using System.ComponentModel;
20 using System.Runtime.InteropServices;
21
22 namespace Tizen.NUI.BaseComponents
23 {
24     /// <summary>
25     /// A control which provides a single line editable text field.
26     /// </summary>
27     /// <since_tizen> 3 </since_tizen>
28     public partial class TextField
29     {
30         private EventHandler<TextChangedEventArgs> textFieldTextChangedEventHandler;
31         private TextChangedCallbackDelegate textFieldTextChangedCallbackDelegate;
32         private EventHandler textFieldCursorPositionChangedEventHandler;
33         private CursorPositionChangedCallbackDelegate textFieldCursorPositionChangedCallbackDelegate;
34         private EventHandler<MaxLengthReachedEventArgs> textFieldMaxLengthReachedEventHandler;
35         private MaxLengthReachedCallbackDelegate textFieldMaxLengthReachedCallbackDelegate;
36         private EventHandler<AnchorClickedEventArgs> textFieldAnchorClickedEventHandler;
37         private AnchorClickedCallbackDelegate textFieldAnchorClickedCallbackDelegate;
38
39         private EventHandler textFieldSelectionChangedEventHandler;
40         private SelectionChangedCallbackDelegate textFieldSelectionChangedCallbackDelegate;
41
42         private EventHandler<InputFilteredEventArgs> textFieldInputFilteredEventHandler;
43         private InputFilteredCallbackDelegate textFieldInputFilteredCallbackDelegate;
44         private EventHandler textFieldSelectionClearedEventHandler;
45         private SelectionClearedCallbackDelegate textFieldSelectionClearedCallbackDelegate;
46
47         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
48         private delegate void TextChangedCallbackDelegate(IntPtr textField);
49
50         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
51         private delegate void CursorPositionChangedCallbackDelegate(IntPtr textField, uint oldPosition);
52
53         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
54         private delegate void MaxLengthReachedCallbackDelegate(IntPtr textField);
55
56         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
57         private delegate void AnchorClickedCallbackDelegate(IntPtr textField, IntPtr href, uint hrefLength);
58
59         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
60         private delegate void SelectionChangedCallbackDelegate(IntPtr textField, uint oldStart, uint oldEnd);
61
62         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
63         private delegate void InputFilteredCallbackDelegate(IntPtr textField, InputFilterType type);
64
65         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
66         private delegate void SelectionClearedCallbackDelegate(IntPtr textField);
67
68         /// <summary>
69         /// The TextChanged event.
70         /// </summary>
71         /// <since_tizen> 3 </since_tizen>
72         public event EventHandler<TextChangedEventArgs> TextChanged
73         {
74             add
75             {
76                 if (textFieldTextChangedEventHandler == null)
77                 {
78                     textFieldTextChangedCallbackDelegate = (OnTextChanged);
79                     TextChangedSignal().Connect(textFieldTextChangedCallbackDelegate);
80                 }
81                 textFieldTextChangedEventHandler += value;
82             }
83             remove
84             {
85                 textFieldTextChangedEventHandler -= value;
86                 if (textFieldTextChangedEventHandler == null && TextChangedSignal().Empty() == false)
87                 {
88                     TextChangedSignal().Disconnect(textFieldTextChangedCallbackDelegate);
89                 }
90             }
91         }
92
93         /// <summary>
94         /// The CursorPositionChanged event.
95         /// </summary>
96         /// This will be public opened after ACR done. Before ACR, need to be hidden as inhouse API.
97         [EditorBrowsable(EditorBrowsableState.Never)]
98         public event EventHandler CursorPositionChanged
99         {
100             add
101             {
102                 if (textFieldCursorPositionChangedEventHandler == null)
103                 {
104                     textFieldCursorPositionChangedCallbackDelegate = (OnCursorPositionChanged);
105                     CursorPositionChangedSignal().Connect(textFieldCursorPositionChangedCallbackDelegate);
106                 }
107                 textFieldCursorPositionChangedEventHandler += value;
108             }
109             remove
110             {
111                 if (textFieldCursorPositionChangedEventHandler == null && CursorPositionChangedSignal().Empty() == false)
112                 {
113                     this.CursorPositionChangedSignal().Disconnect(textFieldCursorPositionChangedCallbackDelegate);
114                 }
115                 textFieldCursorPositionChangedEventHandler -= value;
116             }
117         }
118
119         /// <summary>
120         /// The MaxLengthReached event.
121         /// </summary>
122         /// <since_tizen> 3 </since_tizen>
123         public event EventHandler<MaxLengthReachedEventArgs> MaxLengthReached
124         {
125             add
126             {
127                 if (textFieldMaxLengthReachedEventHandler == null)
128                 {
129                     textFieldMaxLengthReachedCallbackDelegate = (OnMaxLengthReached);
130                     MaxLengthReachedSignal().Connect(textFieldMaxLengthReachedCallbackDelegate);
131                 }
132                 textFieldMaxLengthReachedEventHandler += value;
133             }
134             remove
135             {
136                 if (textFieldMaxLengthReachedEventHandler == null && MaxLengthReachedSignal().Empty() == false)
137                 {
138                     this.MaxLengthReachedSignal().Disconnect(textFieldMaxLengthReachedCallbackDelegate);
139                 }
140                 textFieldMaxLengthReachedEventHandler -= value;
141             }
142         }
143
144         /// <summary>
145         /// The SelectionCleared signal is emitted when selection is cleared.
146         /// </summary>
147         /// This will be public opened after ACR done. Before ACR, need to be hidden as inhouse API.
148         [EditorBrowsable(EditorBrowsableState.Never)]
149         public event EventHandler SelectionCleared
150         {
151             add
152             {
153                 if (textFieldSelectionClearedEventHandler == null)
154                 {
155                     textFieldSelectionClearedCallbackDelegate = (OnSelectionCleared);
156                     SelectionClearedSignal().Connect(textFieldSelectionClearedCallbackDelegate);
157                 }
158                 textFieldSelectionClearedEventHandler += value;
159             }
160             remove
161             {
162                 if (textFieldSelectionClearedEventHandler == null && SelectionClearedSignal().Empty() == false)
163                 {
164                     this.SelectionClearedSignal().Disconnect(textFieldSelectionClearedCallbackDelegate);
165                 }
166                 textFieldSelectionClearedEventHandler -= value;
167             }
168         }
169
170         /// <summary>
171         /// The AnchorClicked signal is emitted when the anchor is clicked.
172         /// </summary>
173         /// <since_tizen> 9 </since_tizen>
174         public event EventHandler<AnchorClickedEventArgs> AnchorClicked
175         {
176             add
177             {
178                 if (textFieldAnchorClickedEventHandler == null)
179                 {
180                     textFieldAnchorClickedCallbackDelegate = (OnAnchorClicked);
181                     AnchorClickedSignal().Connect(textFieldAnchorClickedCallbackDelegate);
182                 }
183                 textFieldAnchorClickedEventHandler += value;
184             }
185             remove
186             {
187                 textFieldAnchorClickedEventHandler -= value;
188                 if (textFieldAnchorClickedEventHandler == null && AnchorClickedSignal().Empty() == false)
189                 {
190                     AnchorClickedSignal().Disconnect(textFieldAnchorClickedCallbackDelegate);
191                 }
192             }
193         }
194
195         /// <summary>
196         /// The SelectionChanged event.
197         /// </summary>
198         /// This will be public opened after ACR done. Before ACR, need to be hidden as inhouse API.
199         /// <since_tizen> 9 </since_tizen>
200         public event EventHandler SelectionChanged
201         {
202             add
203             {
204                 if (textFieldSelectionChangedEventHandler == null)
205                 {
206                     textFieldSelectionChangedCallbackDelegate = (OnSelectionChanged);
207                     SelectionChangedSignal().Connect(textFieldSelectionChangedCallbackDelegate);
208                 }
209                 textFieldSelectionChangedEventHandler += value;
210             }
211             remove
212             {
213                 if (textFieldSelectionChangedEventHandler == null && SelectionChangedSignal().Empty() == false)
214                 {
215                     this.SelectionChangedSignal().Disconnect(textFieldSelectionChangedCallbackDelegate);
216                 }
217                 textFieldSelectionChangedEventHandler -= value;
218             }
219         }
220
221         /// <summary>
222         /// The InputFiltered signal is emitted when the input is filtered by InputFilter. <br />
223         /// </summary>
224         /// <remarks>
225         /// See <see cref="InputFilterType"/> and <see cref="InputFilteredEventArgs"/> for a detailed description. <br />
226         /// </remarks>
227         /// <example>
228         /// The following example demonstrates how to use the InputFiltered event.
229         /// <code>
230         /// field.InputFiltered += (s, e) =>
231         /// {
232         ///     if (e.Type == InputFilterType.Accept)
233         ///     {
234         ///         // If input is filtered by InputFilter of Accept type.
235         ///     }
236         ///     else if (e.Type == InputFilterType.Reject)
237         ///     {
238         ///         // If input is filtered by InputFilter of Reject type.
239         ///     }
240         /// };
241         /// </code>
242         /// </example>
243         [EditorBrowsable(EditorBrowsableState.Never)]
244         public event EventHandler<InputFilteredEventArgs> InputFiltered
245         {
246             add
247             {
248                 if (textFieldInputFilteredEventHandler == null)
249                 {
250                     textFieldInputFilteredCallbackDelegate = (OnInputFiltered);
251                     InputFilteredSignal().Connect(textFieldInputFilteredCallbackDelegate);
252                 }
253                 textFieldInputFilteredEventHandler += value;
254             }
255             remove
256             {
257                 textFieldInputFilteredEventHandler -= value;
258                 if (textFieldInputFilteredEventHandler == null && InputFilteredSignal().Empty() == false)
259                 {
260                     InputFilteredSignal().Disconnect(textFieldInputFilteredCallbackDelegate);
261                 }
262             }
263         }
264
265         internal TextFieldSignal SelectionClearedSignal()
266         {
267             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.SelectionClearedSignal(SwigCPtr), false);
268             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
269             return ret;
270         }
271
272         internal TextFieldSignal TextChangedSignal()
273         {
274             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.TextChangedSignal(SwigCPtr), false);
275             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
276             return ret;
277         }
278
279         internal TextFieldSignal CursorPositionChangedSignal()
280         {
281             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.CursorPositionChangedSignal(SwigCPtr), false);
282             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
283             return ret;
284         }
285
286         internal TextFieldSignal MaxLengthReachedSignal()
287         {
288             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.MaxLengthReachedSignal(SwigCPtr), false);
289             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
290             return ret;
291         }
292
293         internal TextFieldSignal AnchorClickedSignal()
294         {
295             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.AnchorClickedSignal(SwigCPtr), false);
296             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
297             return ret;
298         }
299
300         internal TextFieldSignal SelectionChangedSignal()
301         {
302             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.SelectionChangedSignal(SwigCPtr), false);
303             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
304             return ret;
305         }
306
307         internal TextFieldSignal InputFilteredSignal()
308         {
309             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.InputFilteredSignal(SwigCPtr), false);
310             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
311             return ret;
312         }
313
314         private void OnSelectionCleared(IntPtr textField)
315         {
316             //no data to be sent to the user
317             textFieldSelectionClearedEventHandler?.Invoke(this, EventArgs.Empty);
318         }
319
320         private void OnTextChanged(IntPtr textField)
321         {
322             if (textFieldTextChangedEventHandler != null)
323             {
324                 TextChangedEventArgs e = new TextChangedEventArgs();
325
326                 // Populate all members of "e" (TextChangedEventArgs) with real data
327                 e.TextField = Registry.GetManagedBaseHandleFromNativePtr(textField) as TextField;
328                 //here we send all data to user event handlers
329                 textFieldTextChangedEventHandler(this, e);
330             }
331         }
332
333         private void OnCursorPositionChanged(IntPtr textField, uint oldPosition)
334         {
335             // no data to be sent to the user, as in NUI there is no event provide old values.
336             textFieldCursorPositionChangedEventHandler?.Invoke(this, EventArgs.Empty);
337         }
338
339         private void OnMaxLengthReached(IntPtr textField)
340         {
341             if (textFieldMaxLengthReachedEventHandler != null)
342             {
343                 MaxLengthReachedEventArgs e = new MaxLengthReachedEventArgs();
344
345                 // Populate all members of "e" (MaxLengthReachedEventArgs) with real data
346                 e.TextField = Registry.GetManagedBaseHandleFromNativePtr(textField) as TextField;
347                 //here we send all data to user event handlers
348                 textFieldMaxLengthReachedEventHandler(this, e);
349             }
350         }
351
352         private void OnAnchorClicked(IntPtr textField, IntPtr href, uint hrefLength)
353         {
354             // Note: hrefLength is useful for get the length of a const char* (href) in dali-toolkit.
355             // But NUI can get the length of string (href), so hrefLength is not necessary in NUI.
356             AnchorClickedEventArgs e = new AnchorClickedEventArgs();
357
358             // Populate all members of "e" (AnchorClickedEventArgs) with real data
359             e.Href = Marshal.PtrToStringAnsi(href);
360             //here we send all data to user event handlers
361             textFieldAnchorClickedEventHandler?.Invoke(this, e);
362         }
363
364         private void OnSelectionChanged(IntPtr textField, uint oldStart, uint oldEnd)
365         {
366             // no data to be sent to the user, as in NUI there is no event provide old values.
367             textFieldSelectionChangedEventHandler?.Invoke(this, EventArgs.Empty);
368         }
369
370         private void OnInputFiltered(IntPtr textField, InputFilterType type)
371         {
372             InputFilteredEventArgs e = new InputFilteredEventArgs();
373
374             // Populate all members of "e" (InputFilteredEventArgs) with real data
375             e.Type = type;
376             //here we send all data to user event handlers
377             textFieldInputFilteredEventHandler?.Invoke(this, e);
378         }
379
380         /// <summary>
381         /// The TextChanged event arguments.
382         /// </summary>
383         /// <since_tizen> 3 </since_tizen>
384         public class TextChangedEventArgs : EventArgs
385         {
386             private TextField textField;
387
388             /// <summary>
389             /// TextField.
390             /// </summary>
391             /// <since_tizen> 3 </since_tizen>
392             public TextField TextField
393             {
394                 get
395                 {
396                     return textField;
397                 }
398                 set
399                 {
400                     textField = value;
401                 }
402             }
403         }
404
405         /// <summary>
406         /// The MaxLengthReached event arguments.
407         /// </summary>
408         /// <since_tizen> 3 </since_tizen>
409         public class MaxLengthReachedEventArgs : EventArgs
410         {
411             private TextField textField;
412
413             /// <summary>
414             /// TextField.
415             /// </summary>
416             /// <since_tizen> 3 </since_tizen>
417             public TextField TextField
418             {
419                 get
420                 {
421                     return textField;
422                 }
423                 set
424                 {
425                     textField = value;
426                 }
427             }
428         }
429     }
430 }