/* * 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.InteropServices; using Tizen.NUI; namespace Tizen.NUI.BaseComponents { /// /// AccessibilityRange is used to store data related with Text. /// [EditorBrowsable(EditorBrowsableState.Never)] public class AccessibilityRange { /// /// Start position in stored text. /// public int StartOffset { get; set; } = 0; /// /// End position in stored text. /// public int EndOffset { get; set; } = 0; /// /// Text content in stored text. /// public string Content { get; set; } = ""; } /// /// View is the base class for all views. /// /// 3 public partial class View { /////////////////////////////////////////////////////////////////// // ****************** Accessibility Attributes ****************** // /////////////////////////////////////////////////////////////////// /// /// Dictionary of accessibility attributes (key-value pairs of strings). /// [EditorBrowsable(EditorBrowsableState.Never)] public Dictionary AccessibilityAttributes { get; } = new Dictionary(); /// /// Dictionary of dynamically-evaluated accessibility attributes (key-value pairs of strings). /// [EditorBrowsable(EditorBrowsableState.Never)] public Dictionary> AccessibilityDynamicAttributes { get; } = new Dictionary>(); /////////////////////////////////////////////////////////////////// // ************************** Highlight ************************ // /////////////////////////////////////////////////////////////////// /// /// Clears accessibility highlight. /// /// True if cleared, otherwise false when it is not possible [EditorBrowsable(EditorBrowsableState.Never)] public bool ClearAccessibilityHighlight() { bool result = Interop.ControlDevel.DaliToolkitDevelControlClearAccessibilityHighlight(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return result; } /// /// Grabs accessibility highlight. /// /// True if cleared, otherwise false when it is not possible [EditorBrowsable(EditorBrowsableState.Never)] public bool GrabAccessibilityHighlight() { bool result = Interop.ControlDevel.DaliToolkitDevelControlGrabAccessibilityHighlight(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return result; } /// /// Flag to check whether this view is highlighted or not. /// [EditorBrowsable(EditorBrowsableState.Never)] protected bool IsHighlighted { get { return (this == Accessibility.Accessibility.GetCurrentlyHighlightedView()); } } /////////////////////////////////////////////////////////////////// // ****************** Accessibility Relations ******************* // /////////////////////////////////////////////////////////////////// /// /// Creates relation between objects. /// /// Object which will be in relation. /// Relation type. /// You must pass valid object. NULL could not be in relation. [EditorBrowsable(EditorBrowsableState.Never)] public void AppendAccessibilityRelation(View second, AccessibilityRelationType relation) { if (second is null) { throw new ArgumentNullException(nameof(second)); } Interop.ControlDevel.DaliToolkitDevelControlAppendAccessibilityRelation(SwigCPtr, second.SwigCPtr, (int)relation); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Removes accessibility relation. /// /// Object which will be removed in relation /// Relation type [EditorBrowsable(EditorBrowsableState.Never)] public void RemoveAccessibilityRelation(View second, AccessibilityRelationType relation) { if (second is null) { throw new ArgumentNullException(nameof(second)); } Interop.ControlDevel.DaliToolkitDevelControlRemoveAccessibilityRelation(SwigCPtr, second.SwigCPtr, (int)relation); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Removes all previously appended relations. /// [EditorBrowsable(EditorBrowsableState.Never)] public void ClearAccessibilityRelations() { Interop.ControlDevel.DaliToolkitDevelControlClearAccessibilityRelations(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Gets accessibility collection connected with the current object. /// /// A dictionary mapping a relation type to a set of objects in that relation [EditorBrowsable(EditorBrowsableState.Never)] public Dictionary> GetAccessibilityRelations() { var list = new List>(); var listHandle = GCHandle.Alloc(list); var callback = new Interop.ControlDevel.GetAccessibilityRelationsCallback(GetAccessibilityRelationsCallback); Interop.ControlDevel.DaliToolkitDevelControlGetAccessibilityRelations(SwigCPtr, callback, GCHandle.ToIntPtr(listHandle)); listHandle.Free(); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); var result = new Dictionary>(); foreach (var pair in list) { var key = (AccessibilityRelationType)pair.Key; var value = this.GetInstanceSafely(pair.Value); if (!result.ContainsKey(key)) { result[key] = new List(); } result[key].Add(value); } return result; } private static void GetAccessibilityRelationsCallback(int relationType, IntPtr relationTarget, IntPtr userData) { var handle = GCHandle.FromIntPtr(userData); var list = (List>)handle.Target; list.Add(new KeyValuePair(relationType, relationTarget)); } /////////////////////////////////////////////////////////////////// // ********************* ReadingInfoType *********************** // /////////////////////////////////////////////////////////////////// /// /// Sets accessibility reading information. /// /// Reading information type [EditorBrowsable(EditorBrowsableState.Never)] public void SetAccessibilityReadingInfoTypes(AccessibilityReadingInfoTypes type) { Interop.ControlDevel.DaliToolkitDevelControlSetAccessibilityReadingInfoTypes(SwigCPtr, (int)type); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Gets accessibility reading information. /// /// Reading information type [EditorBrowsable(EditorBrowsableState.Never)] public AccessibilityReadingInfoTypes GetAccessibilityReadingInfoTypes() { AccessibilityReadingInfoTypes result = (AccessibilityReadingInfoTypes)Interop.ControlDevel.DaliToolkitDevelControlGetAccessibilityReadingInfoTypes(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return result; } /////////////////////////////////////////////////////////////////// // ******************** Accessibility States ******************* // /////////////////////////////////////////////////////////////////// /// /// Notifies sending notifications about the current states to accessibility clients. /// /// /// In essence, this is equivalent to calling EmitAccessibilityStateChangedEvent in a loop for all specified states. /// If recursive mode is specified, all children of the Accessibility object will also re-emit the states. /// /// Accessibility States /// Controls the notification strategy [EditorBrowsable(EditorBrowsableState.Never)] public void NotifyAccessibilityStatesChange(AccessibilityStates states, AccessibilityStatesNotifyMode notifyMode) { if (states is null) { throw new ArgumentNullException(nameof(states)); } Interop.ControlDevel.DaliToolkitDevelControlNotifyAccessibilityStateChange(SwigCPtr, states.BitMask, (int)notifyMode); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Gets Accessibility States. /// /// Accessibility States [EditorBrowsable(EditorBrowsableState.Never)] public AccessibilityStates GetAccessibilityStates() { var result = new AccessibilityStates { BitMask = Interop.ControlDevel.DaliToolkitDevelControlGetAccessibilityStates(SwigCPtr) }; if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return result; } /////////////////////////////////////////////////////////////////// // ************************ Accessible ************************* // /////////////////////////////////////////////////////////////////// /// /// Emits accessibility property changed event. /// /// Property changed event [EditorBrowsable(EditorBrowsableState.Never)] public void EmitAccessibilityEvent(AccessibilityPropertyChangeEvent changeEvent) { Interop.ControlDevel.DaliAccessibilityEmitAccessibilityEvent(SwigCPtr, Convert.ToInt32(changeEvent)); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Emits accessibility states changed event. /// /// Accessibility state /// True if the state is set or enabled, otherwise false [EditorBrowsable(EditorBrowsableState.Never)] public void EmitAccessibilityStateChangedEvent(AccessibilityState state, bool equal) { Interop.ControlDevel.DaliAccessibilityEmitAccessibilityStateChangedEvent(SwigCPtr, (int)state, Convert.ToInt32(equal)); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Emits accessibility text inserted event. /// /// Text cursor position /// Text length /// Inserted text content [EditorBrowsable(EditorBrowsableState.Never)] public void EmitTextInsertedEvent(int cursorPosition, int length, string content) { Interop.ControlDevel.DaliAccessibilityEmitTextInsertedEvent(SwigCPtr, cursorPosition, length, content); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Emits accessibility text deleted event. /// /// Text cursor position /// Text length /// Inserted text content [EditorBrowsable(EditorBrowsableState.Never)] public void EmitTextDeletedEvent(int cursorPosition, int length, string content) { Interop.ControlDevel.DaliAccessibilityEmitTextDeletedEvent(SwigCPtr, cursorPosition, length, content); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Emits accessibility text cursor moved event. /// /// The new cursor position [EditorBrowsable(EditorBrowsableState.Never)] public void EmitTextCursorMovedEvent(int cursorPosition) { Interop.ControlDevel.DaliAccessibilityEmitTextCursorMovedEvent(SwigCPtr, cursorPosition); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Modifiable collection of suppressed AT-SPI events (D-Bus signals). /// [EditorBrowsable(EditorBrowsableState.Never)] public AccessibilityEvents AccessibilitySuppressedEvents { get { return new AccessibilityEvents { Owner = this }; } } /////////////////////////////////////////////////////////////////// // ************************** Bridge *************************** // /////////////////////////////////////////////////////////////////// /// /// Registers component as a source of an accessibility "default label". /// The "Default label" is a text that could be read by screen-reader immediately /// after the navigation context has changed (window activates, popup shows up, tab changes) /// and before first UI element is highlighted. /// [EditorBrowsable(EditorBrowsableState.Never)] public void RegisterDefaultLabel() { Interop.ControlDevel.DaliAccessibilityBridgeRegisterDefaultLabel(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Unregisters component that has been registered previously as a source of an accessibility "default label". /// The "Default label" is a text that could be read by screen-reader immediately /// after the navigation context has changed (window activates, popup shows up, tab changes) /// and before first UI element is highlighted. /// [EditorBrowsable(EditorBrowsableState.Never)] public void UnregisterDefaultLabel() { Interop.ControlDevel.DaliAccessibilityBridgeUnregisterDefaultLabel(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } [EditorBrowsable(EditorBrowsableState.Never)] protected override void Dispose(bool disposing) { if (disposed) { return; } internalName = null; if (disposing == false) { if (IsNativeHandleInvalid() || SwigCMemOwn == false) { // at this case, implicit nor explicit dispose is not required. No native object is made. disposed = true; return; } } if (disposing) { Unparent(); } base.Dispose(disposing); } [EditorBrowsable(EditorBrowsableState.Never)] protected static readonly string AccessibilityActivateAction = "activate"; [EditorBrowsable(EditorBrowsableState.Never)] protected static readonly string AccessibilityReadingSkippedAction = "ReadingSkipped"; [EditorBrowsable(EditorBrowsableState.Never)] protected static readonly string AccessibilityReadingCancelledAction = "ReadingCancelled"; [EditorBrowsable(EditorBrowsableState.Never)] protected static readonly string AccessibilityReadingStoppedAction = "ReadingStopped"; [EditorBrowsable(EditorBrowsableState.Never)] protected static readonly string AccessibilityReadingPausedAction = "ReadingPaused"; [EditorBrowsable(EditorBrowsableState.Never)] protected static readonly string AccessibilityReadingResumedAction = "ReadingResumed"; [EditorBrowsable(EditorBrowsableState.Never)] private static readonly string[] AccessibilityActions = { AccessibilityActivateAction, AccessibilityReadingSkippedAction, AccessibilityReadingCancelledAction, AccessibilityReadingStoppedAction, AccessibilityReadingPausedAction, AccessibilityReadingResumedAction, }; [EditorBrowsable(EditorBrowsableState.Never)] protected virtual string AccessibilityGetName() { return ""; } [EditorBrowsable(EditorBrowsableState.Never)] protected virtual string AccessibilityGetDescription() { return ""; } [EditorBrowsable(EditorBrowsableState.Never)] protected virtual bool AccessibilityDoAction(string name) { if (name == AccessibilityActivateAction) { if (ActivateSignal?.Empty() == false) { ActivateSignal?.Emit(); return true; } else { return OnAccessibilityActivated(); } } else if (name == AccessibilityReadingSkippedAction) { if (ReadingSkippedSignal?.Empty() == false) { ReadingSkippedSignal?.Emit(); return true; } else { return OnAccessibilityReadingSkipped(); } } else if (name == AccessibilityReadingCancelledAction) { if (ReadingCancelledSignal?.Empty() == false) { ReadingCancelledSignal?.Emit(); return true; } else { return OnAccessibilityReadingCancelled(); } } else if (name == AccessibilityReadingStoppedAction) { if (ReadingStoppedSignal?.Empty() == false) { ReadingStoppedSignal?.Emit(); return true; } else { return OnAccessibilityReadingStopped(); } } else if (name == AccessibilityReadingPausedAction) { if (ReadingPausedSignal?.Empty() == false) { ReadingPausedSignal?.Emit(); return true; } else { return OnAccessibilityReadingPaused(); } } else if (name == AccessibilityReadingResumedAction) { if (ReadingResumedSignal?.Empty() == false) { ReadingResumedSignal?.Emit(); return true; } else { return OnAccessibilityReadingResumed(); } } else { return false; } } [EditorBrowsable(EditorBrowsableState.Never)] protected virtual AccessibilityStates AccessibilityCalculateStates() { var states = AccessibilityInitialStates; states[AccessibilityState.Focused] = this.State == States.Focused; states[AccessibilityState.Enabled] = this.State != States.Disabled; states[AccessibilityState.Sensitive] = this.Sensitive; return states; } [EditorBrowsable(EditorBrowsableState.Never)] protected virtual int AccessibilityGetActionCount() { return AccessibilityActions.Length; } [EditorBrowsable(EditorBrowsableState.Never)] protected virtual string AccessibilityGetActionName(int index) { if (index >= 0 && index < AccessibilityActions.Length) { return AccessibilityActions[index]; } else { return ""; } } [EditorBrowsable(EditorBrowsableState.Never)] protected virtual bool AccessibilityIsScrollable() { return false; } [EditorBrowsable(EditorBrowsableState.Never)] protected virtual bool AccessibilityScrollToChild(View child) { return false; } /// /// This method is called when the control accessibility is activated.
/// Derived classes should override this to perform custom accessibility activation.
///
/// True if this control can perform accessibility activation. [EditorBrowsable(EditorBrowsableState.Never)] protected virtual bool OnAccessibilityActivated() { return FocusManager.Instance.SetCurrentFocusView(this); } /// /// This method is called when reading is skipped. /// /// True if information was served. [EditorBrowsable(EditorBrowsableState.Never)] protected virtual bool OnAccessibilityReadingSkipped() { return false; } /// /// This method is called when reading is cancelled. /// /// True if information was served. [EditorBrowsable(EditorBrowsableState.Never)] protected virtual bool OnAccessibilityReadingCancelled() { return false; } /// /// This method is called when reading is stopped. /// /// True if information was served. [EditorBrowsable(EditorBrowsableState.Never)] protected virtual bool OnAccessibilityReadingStopped() { return false; } /// /// This method is called when reading was paused. /// /// True if information was served. [EditorBrowsable(EditorBrowsableState.Never)] protected virtual bool OnAccessibilityReadingPaused() { return false; } /// /// This method is called when reading is resumed. /// /// True if information was served. [EditorBrowsable(EditorBrowsableState.Never)] protected virtual bool OnAccessibilityReadingResumed() { return false; } } }