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.

261 lines
8.5KB

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