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.

250 lines
8.2KB

  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. return performActionIfSupported (self, AccessibilityActionType::press);
  103. }
  104. static BOOL accessibilityPerformIncrement (id self, SEL)
  105. {
  106. if (auto* valueInterface = getValueInterface (self))
  107. {
  108. if (! valueInterface->isReadOnly())
  109. {
  110. auto range = valueInterface->getRange();
  111. if (range.isValid())
  112. {
  113. valueInterface->setValue (jlimit (range.getMinimumValue(),
  114. range.getMaximumValue(),
  115. valueInterface->getCurrentValue() + range.getInterval()));
  116. return YES;
  117. }
  118. }
  119. }
  120. return NO;
  121. }
  122. static BOOL accessibilityPerformDecrement (id self, SEL)
  123. {
  124. if (auto* valueInterface = getValueInterface (self))
  125. {
  126. if (! valueInterface->isReadOnly())
  127. {
  128. auto range = valueInterface->getRange();
  129. if (range.isValid())
  130. {
  131. valueInterface->setValue (jlimit (range.getMinimumValue(),
  132. range.getMaximumValue(),
  133. valueInterface->getCurrentValue() - range.getInterval()));
  134. return YES;
  135. }
  136. }
  137. }
  138. return NO;
  139. }
  140. static NSString* getAccessibilityTitle (id self, SEL)
  141. {
  142. if (auto* handler = getHandler (self))
  143. {
  144. auto title = handler->getTitle();
  145. if (title.isEmpty() && handler->getComponent().isOnDesktop())
  146. title = getAccessibleApplicationOrPluginName();
  147. NSString* nsString = juceStringToNS (title);
  148. #if ! JUCE_IOS
  149. if (nsString != nil && [[self accessibilityValue] isEqual: nsString])
  150. return @"";
  151. #endif
  152. return nsString;
  153. }
  154. return nil;
  155. }
  156. static NSString* getAccessibilityHelp (id self, SEL)
  157. {
  158. if (auto* handler = getHandler (self))
  159. return juceStringToNS (handler->getHelp());
  160. return nil;
  161. }
  162. static BOOL getIsAccessibilityModal (id self, SEL)
  163. {
  164. if (auto* handler = getHandler (self))
  165. return handler->getComponent().isCurrentlyModal();
  166. return NO;
  167. }
  168. static NSInteger getAccessibilityRowCount (id self, SEL)
  169. {
  170. if (auto* tableInterface = getTableInterface (self))
  171. return tableInterface->getNumRows();
  172. return 0;
  173. }
  174. static NSInteger getAccessibilityColumnCount (id self, SEL)
  175. {
  176. if (auto* tableInterface = getTableInterface (self))
  177. return tableInterface->getNumColumns();
  178. return 0;
  179. }
  180. static NSRange getAccessibilityRowIndexRange (id self, SEL)
  181. {
  182. if (auto* cellInterface = getCellInterface (self))
  183. return NSMakeRange ((NSUInteger) cellInterface->getRowIndex(),
  184. (NSUInteger) cellInterface->getRowSpan());
  185. return NSMakeRange (0, 0);
  186. }
  187. static NSRange getAccessibilityColumnIndexRange (id self, SEL)
  188. {
  189. if (auto* cellInterface = getCellInterface (self))
  190. return NSMakeRange ((NSUInteger) cellInterface->getColumnIndex(),
  191. (NSUInteger) cellInterface->getColumnSpan());
  192. return NSMakeRange (0, 0);
  193. }
  194. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibleObjCClass)
  195. };
  196. }