The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

254 lines
8.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. //==============================================================================
  21. struct AccessibleObjCClassDeleter
  22. {
  23. template <typename ElementType>
  24. void operator() (ElementType* element) const
  25. {
  26. juceFreeAccessibilityPlatformSpecificData (element);
  27. object_setInstanceVariable (element, "handler", nullptr);
  28. [element release];
  29. }
  30. };
  31. template <typename Base>
  32. class AccessibleObjCClass : public ObjCClass<Base>
  33. {
  34. public:
  35. using Holder = std::unique_ptr<Base, AccessibleObjCClassDeleter>;
  36. protected:
  37. AccessibleObjCClass() : ObjCClass<Base> ("JUCEAccessibilityElement_")
  38. {
  39. ObjCClass<Base>::template addIvar<AccessibilityHandler*> ("handler");
  40. }
  41. //==============================================================================
  42. static AccessibilityHandler* getHandler (id self)
  43. {
  44. return getIvar<AccessibilityHandler*> (self, "handler");
  45. }
  46. template <typename MemberFn>
  47. static auto getInterface (id self, MemberFn fn) noexcept -> decltype ((std::declval<AccessibilityHandler>().*fn)())
  48. {
  49. if (auto* handler = getHandler (self))
  50. return (handler->*fn)();
  51. return nullptr;
  52. }
  53. static AccessibilityTextInterface* getTextInterface (id self) noexcept { return getInterface (self, &AccessibilityHandler::getTextInterface); }
  54. static AccessibilityValueInterface* getValueInterface (id self) noexcept { return getInterface (self, &AccessibilityHandler::getValueInterface); }
  55. static AccessibilityTableInterface* getTableInterface (id self) noexcept { return getInterface (self, &AccessibilityHandler::getTableInterface); }
  56. static AccessibilityCellInterface* getCellInterface (id self) noexcept { return getInterface (self, &AccessibilityHandler::getCellInterface); }
  57. static bool hasEditableText (AccessibilityHandler& handler) noexcept
  58. {
  59. return handler.getRole() == AccessibilityRole::editableText
  60. && handler.getTextInterface() != nullptr
  61. && ! handler.getTextInterface()->isReadOnly();
  62. }
  63. static id getAccessibilityValueFromInterfaces (const AccessibilityHandler& handler)
  64. {
  65. if (auto* textInterface = handler.getTextInterface())
  66. return juceStringToNS (textInterface->getText ({ 0, textInterface->getTotalNumCharacters() }));
  67. if (auto* valueInterface = handler.getValueInterface())
  68. return juceStringToNS (valueInterface->getCurrentValueAsString());
  69. return nil;
  70. }
  71. //==============================================================================
  72. static BOOL getIsAccessibilityElement (id self, SEL)
  73. {
  74. if (auto* handler = getHandler (self))
  75. return ! handler->isIgnored()
  76. && handler->getRole() != AccessibilityRole::window;
  77. return NO;
  78. }
  79. static void setAccessibilityValue (id self, SEL, NSString* value)
  80. {
  81. if (auto* handler = getHandler (self))
  82. {
  83. if (hasEditableText (*handler))
  84. {
  85. handler->getTextInterface()->setText (nsStringToJuce (value));
  86. return;
  87. }
  88. if (auto* valueInterface = handler->getValueInterface())
  89. if (! valueInterface->isReadOnly())
  90. valueInterface->setValueAsString (nsStringToJuce (value));
  91. }
  92. }
  93. static BOOL performActionIfSupported (id self, AccessibilityActionType actionType)
  94. {
  95. if (auto* handler = getHandler (self))
  96. if (handler->getActions().invoke (actionType))
  97. return YES;
  98. return NO;
  99. }
  100. static BOOL accessibilityPerformPress (id self, SEL)
  101. {
  102. if (auto* handler = getHandler (self))
  103. if (handler->getCurrentState().isCheckable() && handler->getActions().invoke (AccessibilityActionType::toggle))
  104. return YES;
  105. return performActionIfSupported (self, AccessibilityActionType::press);
  106. }
  107. static BOOL accessibilityPerformIncrement (id self, SEL)
  108. {
  109. if (auto* valueInterface = getValueInterface (self))
  110. {
  111. if (! valueInterface->isReadOnly())
  112. {
  113. auto range = valueInterface->getRange();
  114. if (range.isValid())
  115. {
  116. valueInterface->setValue (jlimit (range.getMinimumValue(),
  117. range.getMaximumValue(),
  118. valueInterface->getCurrentValue() + range.getInterval()));
  119. return YES;
  120. }
  121. }
  122. }
  123. return NO;
  124. }
  125. static BOOL accessibilityPerformDecrement (id self, SEL)
  126. {
  127. if (auto* valueInterface = getValueInterface (self))
  128. {
  129. if (! valueInterface->isReadOnly())
  130. {
  131. auto range = valueInterface->getRange();
  132. if (range.isValid())
  133. {
  134. valueInterface->setValue (jlimit (range.getMinimumValue(),
  135. range.getMaximumValue(),
  136. valueInterface->getCurrentValue() - range.getInterval()));
  137. return YES;
  138. }
  139. }
  140. }
  141. return NO;
  142. }
  143. static NSString* getAccessibilityTitle (id self, SEL)
  144. {
  145. if (auto* handler = getHandler (self))
  146. {
  147. auto title = handler->getTitle();
  148. if (title.isEmpty() && handler->getComponent().isOnDesktop())
  149. title = getAccessibleApplicationOrPluginName();
  150. NSString* nsString = juceStringToNS (title);
  151. #if ! JUCE_IOS
  152. if (nsString != nil && [[self accessibilityValue] isEqual: nsString])
  153. return @"";
  154. #endif
  155. return nsString;
  156. }
  157. return nil;
  158. }
  159. static NSString* getAccessibilityHelp (id self, SEL)
  160. {
  161. if (auto* handler = getHandler (self))
  162. return juceStringToNS (handler->getHelp());
  163. return nil;
  164. }
  165. static BOOL getIsAccessibilityModal (id self, SEL)
  166. {
  167. if (auto* handler = getHandler (self))
  168. return handler->getComponent().isCurrentlyModal();
  169. return NO;
  170. }
  171. static NSInteger getAccessibilityRowCount (id self, SEL)
  172. {
  173. if (auto* tableInterface = getTableInterface (self))
  174. return tableInterface->getNumRows();
  175. return 0;
  176. }
  177. static NSInteger getAccessibilityColumnCount (id self, SEL)
  178. {
  179. if (auto* tableInterface = getTableInterface (self))
  180. return tableInterface->getNumColumns();
  181. return 0;
  182. }
  183. static NSRange getAccessibilityRowIndexRange (id self, SEL)
  184. {
  185. if (auto* cellInterface = getCellInterface (self))
  186. return NSMakeRange ((NSUInteger) cellInterface->getRowIndex(),
  187. (NSUInteger) cellInterface->getRowSpan());
  188. return NSMakeRange (0, 0);
  189. }
  190. static NSRange getAccessibilityColumnIndexRange (id self, SEL)
  191. {
  192. if (auto* cellInterface = getCellInterface (self))
  193. return NSMakeRange ((NSUInteger) cellInterface->getColumnIndex(),
  194. (NSUInteger) cellInterface->getColumnSpan());
  195. return NSMakeRange (0, 0);
  196. }
  197. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibleObjCClass)
  198. };
  199. }