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.

266 lines
8.8KB

  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. template <typename MemberFn>
  58. static auto getEnclosingInterface (AccessibilityHandler* handler, MemberFn fn) noexcept -> decltype ((std::declval<AccessibilityHandler>().*fn)())
  59. {
  60. if (handler == nullptr)
  61. return nullptr;
  62. if (auto* interface = (handler->*fn)())
  63. return interface;
  64. return getEnclosingInterface (handler->getParent(), fn);
  65. }
  66. static bool hasEditableText (AccessibilityHandler& handler) noexcept
  67. {
  68. return handler.getRole() == AccessibilityRole::editableText
  69. && handler.getTextInterface() != nullptr
  70. && ! handler.getTextInterface()->isReadOnly();
  71. }
  72. static id getAccessibilityValueFromInterfaces (const AccessibilityHandler& handler)
  73. {
  74. if (auto* textInterface = handler.getTextInterface())
  75. return juceStringToNS (textInterface->getText ({ 0, textInterface->getTotalNumCharacters() }));
  76. if (auto* valueInterface = handler.getValueInterface())
  77. return juceStringToNS (valueInterface->getCurrentValueAsString());
  78. return nil;
  79. }
  80. //==============================================================================
  81. static BOOL getIsAccessibilityElement (id self, SEL)
  82. {
  83. if (auto* handler = getHandler (self))
  84. return ! handler->isIgnored()
  85. && handler->getRole() != AccessibilityRole::window;
  86. return NO;
  87. }
  88. static void setAccessibilityValue (id self, SEL, NSString* value)
  89. {
  90. if (auto* handler = getHandler (self))
  91. {
  92. if (hasEditableText (*handler))
  93. {
  94. handler->getTextInterface()->setText (nsStringToJuce (value));
  95. return;
  96. }
  97. if (auto* valueInterface = handler->getValueInterface())
  98. if (! valueInterface->isReadOnly())
  99. valueInterface->setValueAsString (nsStringToJuce (value));
  100. }
  101. }
  102. static BOOL performActionIfSupported (id self, AccessibilityActionType actionType)
  103. {
  104. if (auto* handler = getHandler (self))
  105. if (handler->getActions().invoke (actionType))
  106. return YES;
  107. return NO;
  108. }
  109. static BOOL accessibilityPerformPress (id self, SEL)
  110. {
  111. if (auto* handler = getHandler (self))
  112. if (handler->getCurrentState().isCheckable() && handler->getActions().invoke (AccessibilityActionType::toggle))
  113. return YES;
  114. return performActionIfSupported (self, AccessibilityActionType::press);
  115. }
  116. static BOOL accessibilityPerformIncrement (id self, SEL)
  117. {
  118. if (auto* valueInterface = getValueInterface (self))
  119. {
  120. if (! valueInterface->isReadOnly())
  121. {
  122. auto range = valueInterface->getRange();
  123. if (range.isValid())
  124. {
  125. valueInterface->setValue (jlimit (range.getMinimumValue(),
  126. range.getMaximumValue(),
  127. valueInterface->getCurrentValue() + range.getInterval()));
  128. return YES;
  129. }
  130. }
  131. }
  132. return NO;
  133. }
  134. static BOOL accessibilityPerformDecrement (id self, SEL)
  135. {
  136. if (auto* valueInterface = getValueInterface (self))
  137. {
  138. if (! valueInterface->isReadOnly())
  139. {
  140. auto range = valueInterface->getRange();
  141. if (range.isValid())
  142. {
  143. valueInterface->setValue (jlimit (range.getMinimumValue(),
  144. range.getMaximumValue(),
  145. valueInterface->getCurrentValue() - range.getInterval()));
  146. return YES;
  147. }
  148. }
  149. }
  150. return NO;
  151. }
  152. static NSString* getAccessibilityTitle (id self, SEL)
  153. {
  154. if (auto* handler = getHandler (self))
  155. {
  156. auto title = handler->getTitle();
  157. if (title.isEmpty() && handler->getComponent().isOnDesktop())
  158. title = getAccessibleApplicationOrPluginName();
  159. NSString* nsString = juceStringToNS (title);
  160. #if ! JUCE_IOS
  161. if (nsString != nil && [[self accessibilityValue] isEqual: nsString])
  162. return @"";
  163. #endif
  164. return nsString;
  165. }
  166. return nil;
  167. }
  168. static NSString* getAccessibilityHelp (id self, SEL)
  169. {
  170. if (auto* handler = getHandler (self))
  171. return juceStringToNS (handler->getHelp());
  172. return nil;
  173. }
  174. static BOOL getIsAccessibilityModal (id self, SEL)
  175. {
  176. if (auto* handler = getHandler (self))
  177. return handler->getComponent().isCurrentlyModal();
  178. return NO;
  179. }
  180. static NSInteger getAccessibilityRowCount (id self, SEL)
  181. {
  182. if (auto* tableInterface = getTableInterface (self))
  183. return tableInterface->getNumRows();
  184. return 0;
  185. }
  186. static NSInteger getAccessibilityColumnCount (id self, SEL)
  187. {
  188. if (auto* tableInterface = getTableInterface (self))
  189. return tableInterface->getNumColumns();
  190. return 0;
  191. }
  192. static NSRange getAccessibilityRowIndexRange (id self, SEL)
  193. {
  194. if (auto* cellInterface = getCellInterface (self))
  195. return NSMakeRange ((NSUInteger) cellInterface->getRowIndex(),
  196. (NSUInteger) cellInterface->getRowSpan());
  197. return NSMakeRange (0, 0);
  198. }
  199. static NSRange getAccessibilityColumnIndexRange (id self, SEL)
  200. {
  201. if (auto* cellInterface = getCellInterface (self))
  202. return NSMakeRange ((NSUInteger) cellInterface->getColumnIndex(),
  203. (NSUInteger) cellInterface->getColumnSpan());
  204. return NSMakeRange (0, 0);
  205. }
  206. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibleObjCClass)
  207. };
  208. }