[NUI] Add EmitScrollStartedEvent and EmitScrollFinishedEvent
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / BaseComponents / ViewAccessibility.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.Collections.Generic;
20 using System.ComponentModel;
21 using System.Runtime.InteropServices;
22 using Tizen.NUI;
23
24 namespace Tizen.NUI.BaseComponents
25 {
26     /// <summary>
27     /// AccessibilityRange is used to store data related with Text.
28     /// </summary>
29     [EditorBrowsable(EditorBrowsableState.Never)]
30     public class AccessibilityRange
31     {
32         /// <summary>
33         /// Start position in stored text.
34         /// </summary>
35         public int StartOffset { get; set; } = 0;
36
37         /// <summary>
38         /// End position in stored text.
39         /// </summary>
40         public int EndOffset { get; set; } = 0;
41
42         /// <summary>
43         /// Text content in stored text.
44         /// </summary>
45         public string Content { get; set; } = "";
46     }
47
48     /// <summary>
49     /// View is the base class for all views.
50     /// </summary>
51     /// <since_tizen> 3 </since_tizen>
52     public partial class View
53     {
54         ///////////////////////////////////////////////////////////////////
55         // ****************** Accessibility Attributes ****************** //
56         ///////////////////////////////////////////////////////////////////
57
58         /// <summary>
59         /// Dictionary of accessibility attributes (key-value pairs of strings).
60         /// </summary>
61         [EditorBrowsable(EditorBrowsableState.Never)]
62         protected Dictionary<string, string> AccessibilityAttributes { get; } = new Dictionary<string, string>();
63
64         ///////////////////////////////////////////////////////////////////
65         // ************************** Highlight ************************ //
66         ///////////////////////////////////////////////////////////////////
67
68         /// <summary>
69         /// Clears accessibility highlight.
70         /// </summary>
71         /// <returns>True if cleared, otherwise false when it is not possible</returns>
72         [EditorBrowsable(EditorBrowsableState.Never)]
73         public bool ClearAccessibilityHighlight()
74         {
75             bool result = Interop.ControlDevel.DaliToolkitDevelControlClearAccessibilityHighlight(SwigCPtr);
76             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
77             return result;
78         }
79
80         /// <summary>
81         /// Grabs accessibility highlight.
82         /// </summary>
83         /// <returns>True if cleared, otherwise false when it is not possible</returns>
84         [EditorBrowsable(EditorBrowsableState.Never)]
85         public bool GrabAccessibilityHighlight()
86         {
87             bool result = Interop.ControlDevel.DaliToolkitDevelControlGrabAccessibilityHighlight(SwigCPtr);
88             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
89             return result;
90         }
91
92         /// <summary>
93         /// Flag to check whether this view is highlighted or not.
94         /// </summary>
95         [EditorBrowsable(EditorBrowsableState.Never)]
96         protected bool IsHighlighted
97         {
98             get
99             {
100                 return (this == Accessibility.Accessibility.GetCurrentlyHighlightedView());
101             }
102         }
103
104         ///////////////////////////////////////////////////////////////////
105         // ****************** Accessibility Relations ******************* //
106         ///////////////////////////////////////////////////////////////////
107
108         /// <summary>
109         /// Creates relation between objects.
110         /// </summary>
111         /// <param name="second">Object which will be in relation.</param>
112         /// <param name="relation">Relation type.</param>
113         /// <exception cref="ArgumentNullException">You must pass valid object. NULL could not be in relation.</exception>
114         [EditorBrowsable(EditorBrowsableState.Never)]
115         public void AppendAccessibilityRelation(View second, AccessibilityRelationType relation)
116         {
117             if (second is null)
118             {
119                 throw new ArgumentNullException(nameof(second));
120             }
121
122             Interop.ControlDevel.DaliToolkitDevelControlAppendAccessibilityRelation(SwigCPtr, second.SwigCPtr, (int)relation);
123             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
124         }
125
126         /// <summary>
127         /// Removes accessibility relation.
128         /// </summary>
129         /// <param name="second">Object which will be removed in relation</param>
130         /// <param name="relation">Relation type</param>
131         [EditorBrowsable(EditorBrowsableState.Never)]
132         public void RemoveAccessibilityRelation(View second, AccessibilityRelationType relation)
133         {
134             if (second is null)
135             {
136                 throw new ArgumentNullException(nameof(second));
137             }
138
139             Interop.ControlDevel.DaliToolkitDevelControlRemoveAccessibilityRelation(SwigCPtr, second.SwigCPtr, (int)relation);
140             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
141         }
142
143         /// <summary>
144         /// Removes all previously appended relations.
145         /// </summary>
146         [EditorBrowsable(EditorBrowsableState.Never)]
147         public void ClearAccessibilityRelations()
148         {
149             Interop.ControlDevel.DaliToolkitDevelControlClearAccessibilityRelations(SwigCPtr);
150             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
151         }
152
153         /// <summary>
154         /// Gets accessibility collection connected with the current object.
155         /// </summary>
156         /// <returns>A dictionary mapping a relation type to a set of objects in that relation</returns>
157         [EditorBrowsable(EditorBrowsableState.Never)]
158         public Dictionary<AccessibilityRelationType, List<View>> GetAccessibilityRelations()
159         {
160             var list = new List<KeyValuePair<int, IntPtr>>();
161             var listHandle = GCHandle.Alloc(list);
162             var callback = new Interop.ControlDevel.GetAccessibilityRelationsCallback(GetAccessibilityRelationsCallback);
163
164             Interop.ControlDevel.DaliToolkitDevelControlGetAccessibilityRelations(SwigCPtr, callback, GCHandle.ToIntPtr(listHandle));
165             listHandle.Free();
166             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
167
168             var result = new Dictionary<AccessibilityRelationType, List<View>>();
169
170             foreach (var pair in list)
171             {
172                 var key = (AccessibilityRelationType)pair.Key;
173                 var value = this.GetInstanceSafely<View>(pair.Value);
174
175                 if (!result.ContainsKey(key))
176                 {
177                     result[key] = new List<View>();
178                 }
179
180                 result[key].Add(value);
181             }
182
183             return result;
184         }
185
186         private static void GetAccessibilityRelationsCallback(int relationType, IntPtr relationTarget, IntPtr userData)
187         {
188             var handle = GCHandle.FromIntPtr(userData);
189             var list = (List<KeyValuePair<int, IntPtr>>)handle.Target;
190
191             list.Add(new KeyValuePair<int, IntPtr>(relationType, relationTarget));
192         }
193
194         ///////////////////////////////////////////////////////////////////
195         // ********************* ReadingInfoType *********************** //
196         ///////////////////////////////////////////////////////////////////
197
198         /// <summary>
199         /// Sets accessibility reading information.
200         /// </summary>
201         /// <param name="type">Reading information type</param>
202         [EditorBrowsable(EditorBrowsableState.Never)]
203         public void SetAccessibilityReadingInfoTypes(AccessibilityReadingInfoTypes type)
204         {
205             Interop.ControlDevel.DaliToolkitDevelControlSetAccessibilityReadingInfoTypes(SwigCPtr, (int)type);
206             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
207         }
208
209         /// <summary>
210         /// Gets accessibility reading information.
211         /// </summary>
212         /// <returns>Reading information type</returns>
213         [EditorBrowsable(EditorBrowsableState.Never)]
214         public AccessibilityReadingInfoTypes GetAccessibilityReadingInfoTypes()
215         {
216             AccessibilityReadingInfoTypes result = (AccessibilityReadingInfoTypes)Interop.ControlDevel.DaliToolkitDevelControlGetAccessibilityReadingInfoTypes(SwigCPtr);
217             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
218             return result;
219         }
220
221         ///////////////////////////////////////////////////////////////////
222         // ******************** Accessibility States ******************* //
223         ///////////////////////////////////////////////////////////////////
224
225         /// <summary>
226         /// Notifies sending notifications about the current states to accessibility clients.
227         /// </summary>
228         /// <remarks>
229         /// In essence, this is equivalent to calling EmitAccessibilityStateChangedEvent in a loop for all specified states.
230         /// If recursive mode is specified, all children of the Accessibility object will also re-emit the states.
231         /// </remarks>
232         /// <param name="states">Accessibility States</param>
233         /// <param name="notifyMode">Controls the notification strategy</param>
234         [EditorBrowsable(EditorBrowsableState.Never)]
235         public void NotifyAccessibilityStatesChange(AccessibilityStates states, AccessibilityStatesNotifyMode notifyMode)
236         {
237             if (states is null)
238             {
239                 throw new ArgumentNullException(nameof(states));
240             }
241
242             Interop.ControlDevel.DaliToolkitDevelControlNotifyAccessibilityStateChange(SwigCPtr, states.BitMask, (int)notifyMode);
243             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
244         }
245
246         /// <summary>
247         /// Gets Accessibility States.
248         /// </summary>
249         /// <returns>Accessibility States</returns>
250         [EditorBrowsable(EditorBrowsableState.Never)]
251         public AccessibilityStates GetAccessibilityStates()
252         {
253             var result = new AccessibilityStates {BitMask = Interop.ControlDevel.DaliToolkitDevelControlGetAccessibilityStates(SwigCPtr)};
254             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
255             return result;
256         }
257
258         ///////////////////////////////////////////////////////////////////
259         // ************************ Accessible ************************* //
260         ///////////////////////////////////////////////////////////////////
261
262         /// <summary>
263         /// Emits accessibility property changed event.
264         /// </summary>
265         /// <param name="changeEvent">Property changed event</param>
266         [EditorBrowsable(EditorBrowsableState.Never)]
267         public void EmitAccessibilityEvent(AccessibilityPropertyChangeEvent changeEvent)
268         {
269             Interop.ControlDevel.DaliAccessibilityEmitAccessibilityEvent(SwigCPtr, Convert.ToInt32(changeEvent));
270             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
271         }
272
273         /// <summary>
274         /// Emits accessibility states changed event.
275         /// </summary>
276         /// <param name="state">Accessibility state</param>
277         /// <param name="equal">True if the state is set or enabled, otherwise false</param>
278         [EditorBrowsable(EditorBrowsableState.Never)]
279         public void EmitAccessibilityStateChangedEvent(AccessibilityState state, bool equal)
280         {
281             Interop.ControlDevel.DaliAccessibilityEmitAccessibilityStateChangedEvent(SwigCPtr, (int)state, Convert.ToInt32(equal));
282             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
283         }
284
285         /// <summary>
286         /// Emits accessibility text inserted event.
287         /// </summary>
288         /// <param name="cursorPosition">Text cursor position</param>
289         /// <param name="length">Text length</param>
290         /// <param name="content">Inserted text content</param>
291         [EditorBrowsable(EditorBrowsableState.Never)]
292         public void EmitTextInsertedEvent(int cursorPosition, int length, string content)
293         {
294             Interop.ControlDevel.DaliAccessibilityEmitTextInsertedEvent(SwigCPtr, cursorPosition, length, content);
295             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
296         }
297
298         /// <summary>
299         /// Emits accessibility text deleted event.
300         /// </summary>
301         /// <param name="cursorPosition">Text cursor position</param>
302         /// <param name="length">Text length</param>
303         /// <param name="content">Inserted text content</param>
304         [EditorBrowsable(EditorBrowsableState.Never)]
305         public void EmitTextDeletedEvent(int cursorPosition, int length, string content)
306         {
307             Interop.ControlDevel.DaliAccessibilityEmitTextDeletedEvent(SwigCPtr, cursorPosition, length, content);
308             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
309         }
310
311         /// <summary>
312         /// Emits accessibility text cursor moved event.
313         /// </summary>
314         /// <param name="cursorPosition">The new cursor position</param>
315         [EditorBrowsable(EditorBrowsableState.Never)]
316         public void EmitTextCursorMovedEvent(int cursorPosition)
317         {
318             Interop.ControlDevel.DaliAccessibilityEmitTextCursorMovedEvent(SwigCPtr, cursorPosition);
319             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
320         }
321
322         /// <summary>
323         /// Emits accessibility scroll started event.
324         /// </summary>
325         [EditorBrowsable(EditorBrowsableState.Never)]
326         public void EmitScrollStartedEvent()
327         {
328             Interop.ControlDevel.DaliAccessibilityEmitScrollStartedEvent(SwigCPtr);
329             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
330         }
331
332         /// <summary>
333         /// Emits accessibility scroll finished event.
334         /// </summary>
335         [EditorBrowsable(EditorBrowsableState.Never)]
336         public void EmitScrollFinishedEvent()
337         {
338             Interop.ControlDevel.DaliAccessibilityEmitScrollFinishedEvent(SwigCPtr);
339             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
340         }
341
342         /// <summary>
343         /// Modifiable collection of suppressed AT-SPI events (D-Bus signals).
344         /// </summary>
345         [EditorBrowsable(EditorBrowsableState.Never)]
346         public AccessibilityEvents AccessibilitySuppressedEvents
347         {
348             get
349             {
350                 return new AccessibilityEvents {Owner = this};
351             }
352         }
353
354         ///////////////////////////////////////////////////////////////////
355         // ************************** Bridge *************************** //
356         ///////////////////////////////////////////////////////////////////
357
358         /// <summary>
359         /// Registers component as a source of an accessibility "default label".
360         /// The "Default label" is a text that could be read by screen-reader immediately
361         /// after the navigation context has changed (window activates, popup shows up, tab changes)
362         /// and before first UI element is highlighted.
363         /// </summary>
364         [EditorBrowsable(EditorBrowsableState.Never)]
365         public void RegisterDefaultLabel()
366         {
367             Interop.ControlDevel.DaliAccessibilityBridgeRegisterDefaultLabel(SwigCPtr);
368             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
369         }
370
371         /// <summary>
372         /// Unregisters component that has been registered previously as a source of an accessibility "default label".
373         /// The "Default label" is a text that could be read by screen-reader immediately
374         /// after the navigation context has changed (window activates, popup shows up, tab changes)
375         /// and before first UI element is highlighted.
376         /// </summary>
377         [EditorBrowsable(EditorBrowsableState.Never)]
378         public void UnregisterDefaultLabel()
379         {
380             Interop.ControlDevel.DaliAccessibilityBridgeUnregisterDefaultLabel(SwigCPtr);
381             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
382         }
383
384         [EditorBrowsable(EditorBrowsableState.Never)]
385         protected override void Dispose(bool disposing)
386         {
387             if (disposed)
388             {
389                 return;
390             }
391
392             internalName = null;
393
394             if (disposing == false)
395             {
396                 if (IsNativeHandleInvalid() || SwigCMemOwn == false)
397                 {
398                     // at this case, implicit nor explicit dispose is not required. No native object is made.
399                     disposed = true;
400                     return;
401                 }
402             }
403
404             if (disposing)
405             {
406                 Unparent();
407             }
408
409             base.Dispose(disposing);
410         }
411
412         [EditorBrowsable(EditorBrowsableState.Never)]
413         protected static readonly string AccessibilityActivateAction = "activate";
414         [EditorBrowsable(EditorBrowsableState.Never)]
415         protected static readonly string AccessibilityReadingSkippedAction = "ReadingSkipped";
416         [EditorBrowsable(EditorBrowsableState.Never)]
417         protected static readonly string AccessibilityReadingCancelledAction = "ReadingCancelled";
418         [EditorBrowsable(EditorBrowsableState.Never)]
419         protected static readonly string AccessibilityReadingStoppedAction = "ReadingStopped";
420         [EditorBrowsable(EditorBrowsableState.Never)]
421         protected static readonly string AccessibilityReadingPausedAction = "ReadingPaused";
422         [EditorBrowsable(EditorBrowsableState.Never)]
423         protected static readonly string AccessibilityReadingResumedAction = "ReadingResumed";
424
425         [EditorBrowsable(EditorBrowsableState.Never)]
426         private static readonly string[] AccessibilityActions = {
427             AccessibilityActivateAction,
428             AccessibilityReadingSkippedAction,
429             AccessibilityReadingCancelledAction,
430             AccessibilityReadingStoppedAction,
431             AccessibilityReadingPausedAction,
432             AccessibilityReadingResumedAction,
433         };
434
435         [EditorBrowsable(EditorBrowsableState.Never)]
436         protected virtual string AccessibilityGetName()
437         {
438             return "";
439         }
440
441         [EditorBrowsable(EditorBrowsableState.Never)]
442         protected virtual string AccessibilityGetDescription()
443         {
444             return "";
445         }
446
447         [EditorBrowsable(EditorBrowsableState.Never)]
448         protected virtual bool AccessibilityDoAction(string name)
449         {
450             return false;
451         }
452
453         [EditorBrowsable(EditorBrowsableState.Never)]
454         protected virtual AccessibilityStates AccessibilityCalculateStates()
455         {
456             var states = AccessibilityInitialStates;
457
458             states[AccessibilityState.Focused] = this.State == States.Focused;
459             states[AccessibilityState.Enabled] = this.State != States.Disabled;
460             states[AccessibilityState.Sensitive] = this.Sensitive;
461
462             return states;
463         }
464
465         [EditorBrowsable(EditorBrowsableState.Never)]
466         protected virtual int AccessibilityGetActionCount()
467         {
468             return AccessibilityActions.Length;
469         }
470
471         [EditorBrowsable(EditorBrowsableState.Never)]
472         protected virtual string AccessibilityGetActionName(int index)
473         {
474             if (index >= 0 && index < AccessibilityActions.Length)
475             {
476                 return AccessibilityActions[index];
477             }
478             else
479             {
480                 return "";
481             }
482         }
483
484         [EditorBrowsable(EditorBrowsableState.Never)]
485         protected virtual bool AccessibilityIsScrollable()
486         {
487             return false;
488         }
489
490         [EditorBrowsable(EditorBrowsableState.Never)]
491         protected virtual bool AccessibilityScrollToChild(View child)
492         {
493             return false;
494         }
495     }
496 }