[NUI] Add SelectionStarted event (#3912)
[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         private EventHandler textFieldSelectionStartedEventHandler;
48         private SelectionStartedCallbackDelegate textFieldSelectionStartedCallbackDelegate;
49
50         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
51         private delegate void TextChangedCallbackDelegate(IntPtr textField);
52
53         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
54         private delegate void CursorPositionChangedCallbackDelegate(IntPtr textField, uint oldPosition);
55
56         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
57         private delegate void MaxLengthReachedCallbackDelegate(IntPtr textField);
58
59         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
60         private delegate void AnchorClickedCallbackDelegate(IntPtr textField, IntPtr href, uint hrefLength);
61
62         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
63         private delegate void SelectionChangedCallbackDelegate(IntPtr textField, uint oldStart, uint oldEnd);
64
65         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
66         private delegate void InputFilteredCallbackDelegate(IntPtr textField, InputFilterType type);
67
68         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
69         private delegate void SelectionClearedCallbackDelegate(IntPtr textField);
70
71         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
72         private delegate void SelectionStartedCallbackDelegate(IntPtr textField);
73
74         private bool invokeTextChanged = true;
75
76         /// <summary>
77         /// The TextChanged event.
78         /// </summary>
79         /// <since_tizen> 3 </since_tizen>
80         public event EventHandler<TextChangedEventArgs> TextChanged
81         {
82             add
83             {
84                 if (textFieldTextChangedEventHandler == null)
85                 {
86                     textFieldTextChangedCallbackDelegate = (OnTextChanged);
87                     TextChangedSignal().Connect(textFieldTextChangedCallbackDelegate);
88                 }
89                 textFieldTextChangedEventHandler += value;
90             }
91             remove
92             {
93                 textFieldTextChangedEventHandler -= value;
94                 if (textFieldTextChangedEventHandler == null && TextChangedSignal().Empty() == false)
95                 {
96                     TextChangedSignal().Disconnect(textFieldTextChangedCallbackDelegate);
97                 }
98             }
99         }
100
101         /// <summary>
102         /// The CursorPositionChanged event is emitted whenever the primary cursor position changed.
103         /// </summary>
104         /// <since_tizen> 9 </since_tizen>
105         public event EventHandler CursorPositionChanged
106         {
107             add
108             {
109                 if (textFieldCursorPositionChangedEventHandler == null)
110                 {
111                     textFieldCursorPositionChangedCallbackDelegate = (OnCursorPositionChanged);
112                     CursorPositionChangedSignal().Connect(textFieldCursorPositionChangedCallbackDelegate);
113                 }
114                 textFieldCursorPositionChangedEventHandler += value;
115             }
116             remove
117             {
118                 if (textFieldCursorPositionChangedEventHandler == null && CursorPositionChangedSignal().Empty() == false)
119                 {
120                     this.CursorPositionChangedSignal().Disconnect(textFieldCursorPositionChangedCallbackDelegate);
121                 }
122                 textFieldCursorPositionChangedEventHandler -= value;
123             }
124         }
125
126         /// <summary>
127         /// The MaxLengthReached event.
128         /// </summary>
129         /// <since_tizen> 3 </since_tizen>
130         public event EventHandler<MaxLengthReachedEventArgs> MaxLengthReached
131         {
132             add
133             {
134                 if (textFieldMaxLengthReachedEventHandler == null)
135                 {
136                     textFieldMaxLengthReachedCallbackDelegate = (OnMaxLengthReached);
137                     MaxLengthReachedSignal().Connect(textFieldMaxLengthReachedCallbackDelegate);
138                 }
139                 textFieldMaxLengthReachedEventHandler += value;
140             }
141             remove
142             {
143                 if (textFieldMaxLengthReachedEventHandler == null && MaxLengthReachedSignal().Empty() == false)
144                 {
145                     this.MaxLengthReachedSignal().Disconnect(textFieldMaxLengthReachedCallbackDelegate);
146                 }
147                 textFieldMaxLengthReachedEventHandler -= value;
148             }
149         }
150
151         /// <summary>
152         /// The SelectionStarted event is emitted when the selection start.
153         /// </summary>
154         /// This will be public opened in after ACR done. Before ACR, need to be hidden as inhouse API.
155         [EditorBrowsable(EditorBrowsableState.Never)]
156         public event EventHandler SelectionStarted
157         {
158             add
159             {
160                 if (textFieldSelectionStartedEventHandler == null)
161                 {
162                     textFieldSelectionStartedCallbackDelegate = (OnSelectionStarted);
163                     SelectionStartedSignal().Connect(textFieldSelectionStartedCallbackDelegate);
164                 }
165                 textFieldSelectionStartedEventHandler += value;
166             }
167             remove
168             {
169                 if (textFieldSelectionStartedEventHandler == null && SelectionStartedSignal().Empty() == false)
170                 {
171                     this.SelectionStartedSignal().Disconnect(textFieldSelectionStartedCallbackDelegate);
172                 }
173                 textFieldSelectionStartedEventHandler -= value;
174             }
175         }
176
177         /// <summary>
178         /// The SelectionCleared signal is emitted when selection is cleared.
179         /// </summary>
180         /// <since_tizen> 9 </since_tizen>
181         public event EventHandler SelectionCleared
182         {
183             add
184             {
185                 if (textFieldSelectionClearedEventHandler == null)
186                 {
187                     textFieldSelectionClearedCallbackDelegate = (OnSelectionCleared);
188                     SelectionClearedSignal().Connect(textFieldSelectionClearedCallbackDelegate);
189                 }
190                 textFieldSelectionClearedEventHandler += value;
191             }
192             remove
193             {
194                 if (textFieldSelectionClearedEventHandler == null && SelectionClearedSignal().Empty() == false)
195                 {
196                     this.SelectionClearedSignal().Disconnect(textFieldSelectionClearedCallbackDelegate);
197                 }
198                 textFieldSelectionClearedEventHandler -= value;
199             }
200         }
201
202         /// <summary>
203         /// The AnchorClicked signal is emitted when the anchor is clicked.
204         /// </summary>
205         /// <since_tizen> 9 </since_tizen>
206         public event EventHandler<AnchorClickedEventArgs> AnchorClicked
207         {
208             add
209             {
210                 if (textFieldAnchorClickedEventHandler == null)
211                 {
212                     textFieldAnchorClickedCallbackDelegate = (OnAnchorClicked);
213                     AnchorClickedSignal().Connect(textFieldAnchorClickedCallbackDelegate);
214                 }
215                 textFieldAnchorClickedEventHandler += value;
216             }
217             remove
218             {
219                 textFieldAnchorClickedEventHandler -= value;
220                 if (textFieldAnchorClickedEventHandler == null && AnchorClickedSignal().Empty() == false)
221                 {
222                     AnchorClickedSignal().Disconnect(textFieldAnchorClickedCallbackDelegate);
223                 }
224             }
225         }
226
227         /// <summary>
228         /// The SelectionChanged event is emitted whenever the selected text is changed.
229         /// </summary>
230         /// <since_tizen> 9 </since_tizen>
231         public event EventHandler SelectionChanged
232         {
233             add
234             {
235                 if (textFieldSelectionChangedEventHandler == null)
236                 {
237                     textFieldSelectionChangedCallbackDelegate = (OnSelectionChanged);
238                     SelectionChangedSignal().Connect(textFieldSelectionChangedCallbackDelegate);
239                 }
240                 textFieldSelectionChangedEventHandler += value;
241             }
242             remove
243             {
244                 if (textFieldSelectionChangedEventHandler == null && SelectionChangedSignal().Empty() == false)
245                 {
246                     this.SelectionChangedSignal().Disconnect(textFieldSelectionChangedCallbackDelegate);
247                 }
248                 textFieldSelectionChangedEventHandler -= value;
249             }
250         }
251
252         /// <summary>
253         /// The InputFiltered signal is emitted when the input is filtered by InputFilter. <br />
254         /// </summary>
255         /// <remarks>
256         /// See <see cref="InputFilterType"/> and <see cref="InputFilteredEventArgs"/> for a detailed description. <br />
257         /// </remarks>
258         /// <example>
259         /// The following example demonstrates how to use the InputFiltered event.
260         /// <code>
261         /// field.InputFiltered += (s, e) =>
262         /// {
263         ///     if (e.Type == InputFilterType.Accept)
264         ///     {
265         ///         // If input is filtered by InputFilter of Accept type.
266         ///     }
267         ///     else if (e.Type == InputFilterType.Reject)
268         ///     {
269         ///         // If input is filtered by InputFilter of Reject type.
270         ///     }
271         /// };
272         /// </code>
273         /// </example>
274         /// <since_tizen> 9 </since_tizen>
275         public event EventHandler<InputFilteredEventArgs> InputFiltered
276         {
277             add
278             {
279                 if (textFieldInputFilteredEventHandler == null)
280                 {
281                     textFieldInputFilteredCallbackDelegate = (OnInputFiltered);
282                     InputFilteredSignal().Connect(textFieldInputFilteredCallbackDelegate);
283                 }
284                 textFieldInputFilteredEventHandler += value;
285             }
286             remove
287             {
288                 textFieldInputFilteredEventHandler -= value;
289                 if (textFieldInputFilteredEventHandler == null && InputFilteredSignal().Empty() == false)
290                 {
291                     InputFilteredSignal().Disconnect(textFieldInputFilteredCallbackDelegate);
292                 }
293             }
294         }
295
296         internal TextFieldSignal SelectionStartedSignal()
297         {
298             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.SelectionStartedSignal(SwigCPtr), false);
299             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
300             return ret;
301         }
302
303         internal TextFieldSignal SelectionClearedSignal()
304         {
305             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.SelectionClearedSignal(SwigCPtr), false);
306             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
307             return ret;
308         }
309
310         internal TextFieldSignal TextChangedSignal()
311         {
312             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.TextChangedSignal(SwigCPtr), false);
313             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
314             return ret;
315         }
316
317         internal TextFieldSignal CursorPositionChangedSignal()
318         {
319             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.CursorPositionChangedSignal(SwigCPtr), false);
320             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
321             return ret;
322         }
323
324         internal TextFieldSignal MaxLengthReachedSignal()
325         {
326             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.MaxLengthReachedSignal(SwigCPtr), false);
327             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
328             return ret;
329         }
330
331         internal TextFieldSignal AnchorClickedSignal()
332         {
333             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.AnchorClickedSignal(SwigCPtr), false);
334             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
335             return ret;
336         }
337
338         internal TextFieldSignal SelectionChangedSignal()
339         {
340             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.SelectionChangedSignal(SwigCPtr), false);
341             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
342             return ret;
343         }
344
345         internal TextFieldSignal InputFilteredSignal()
346         {
347             TextFieldSignal ret = new TextFieldSignal(Interop.TextField.InputFilteredSignal(SwigCPtr), false);
348             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
349             return ret;
350         }
351
352         private void OnSelectionStarted(IntPtr textField)
353         {
354             //no data to be sent to the user
355             textFieldSelectionStartedEventHandler?.Invoke(this, EventArgs.Empty);
356         }
357
358         private void OnSelectionCleared(IntPtr textField)
359         {
360             //no data to be sent to the user
361             textFieldSelectionClearedEventHandler?.Invoke(this, EventArgs.Empty);
362         }
363
364         private void OnTextChanged(IntPtr textField)
365         {
366             if (textFieldTextChangedEventHandler != null && invokeTextChanged)
367             {
368                 TextChangedEventArgs e = new TextChangedEventArgs();
369
370                 // Populate all members of "e" (TextChangedEventArgs) with real data
371                 e.TextField = Registry.GetManagedBaseHandleFromNativePtr(textField) as TextField;
372                 //here we send all data to user event handlers
373                 textFieldTextChangedEventHandler(this, e);
374             }
375         }
376
377         private void OnCursorPositionChanged(IntPtr textField, uint oldPosition)
378         {
379             // no data to be sent to the user, as in NUI there is no event provide old values.
380             textFieldCursorPositionChangedEventHandler?.Invoke(this, EventArgs.Empty);
381         }
382
383         private void OnMaxLengthReached(IntPtr textField)
384         {
385             if (textFieldMaxLengthReachedEventHandler != null)
386             {
387                 MaxLengthReachedEventArgs e = new MaxLengthReachedEventArgs();
388
389                 // Populate all members of "e" (MaxLengthReachedEventArgs) with real data
390                 e.TextField = Registry.GetManagedBaseHandleFromNativePtr(textField) as TextField;
391                 //here we send all data to user event handlers
392                 textFieldMaxLengthReachedEventHandler(this, e);
393             }
394         }
395
396         private void OnAnchorClicked(IntPtr textField, IntPtr href, uint hrefLength)
397         {
398             // Note: hrefLength is useful for get the length of a const char* (href) in dali-toolkit.
399             // But NUI can get the length of string (href), so hrefLength is not necessary in NUI.
400             AnchorClickedEventArgs e = new AnchorClickedEventArgs();
401
402             // Populate all members of "e" (AnchorClickedEventArgs) with real data
403             e.Href = Marshal.PtrToStringAnsi(href);
404             //here we send all data to user event handlers
405             textFieldAnchorClickedEventHandler?.Invoke(this, e);
406         }
407
408         private void OnSelectionChanged(IntPtr textField, uint oldStart, uint oldEnd)
409         {
410             // no data to be sent to the user, as in NUI there is no event provide old values.
411             textFieldSelectionChangedEventHandler?.Invoke(this, EventArgs.Empty);
412         }
413
414         private void OnInputFiltered(IntPtr textField, InputFilterType type)
415         {
416             InputFilteredEventArgs e = new InputFilteredEventArgs();
417
418             // Populate all members of "e" (InputFilteredEventArgs) with real data
419             e.Type = type;
420             //here we send all data to user event handlers
421             textFieldInputFilteredEventHandler?.Invoke(this, e);
422         }
423
424         /// <summary>
425         /// The TextChanged event arguments.
426         /// </summary>
427         /// <since_tizen> 3 </since_tizen>
428         public class TextChangedEventArgs : EventArgs
429         {
430             private TextField textField;
431
432             /// <summary>
433             /// TextField.
434             /// </summary>
435             /// <since_tizen> 3 </since_tizen>
436             public TextField TextField
437             {
438                 get
439                 {
440                     return textField;
441                 }
442                 set
443                 {
444                     textField = value;
445                 }
446             }
447         }
448
449         /// <summary>
450         /// The MaxLengthReached event arguments.
451         /// </summary>
452         /// <since_tizen> 3 </since_tizen>
453         public class MaxLengthReachedEventArgs : EventArgs
454         {
455             private TextField textField;
456
457             /// <summary>
458             /// TextField.
459             /// </summary>
460             /// <since_tizen> 3 </since_tizen>
461             public TextField TextField
462             {
463                 get
464                 {
465                     return textField;
466                 }
467                 set
468                 {
469                     textField = value;
470                 }
471             }
472         }
473     }
474 }