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.

341 lines
10KB

  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. AccessibilityHandler* AccessibilityHandler::currentlyFocusedHandler = nullptr;
  21. enum class InternalAccessibilityEvent
  22. {
  23. elementCreated,
  24. elementDestroyed,
  25. elementMovedOrResized,
  26. focusChanged,
  27. windowOpened,
  28. windowClosed
  29. };
  30. void notifyAccessibilityEventInternal (const AccessibilityHandler&, InternalAccessibilityEvent);
  31. inline String getAccessibleApplicationOrPluginName()
  32. {
  33. #if defined (JucePlugin_Name)
  34. return JucePlugin_Name;
  35. #else
  36. if (auto* app = JUCEApplicationBase::getInstance())
  37. return app->getApplicationName();
  38. return "JUCE Application";
  39. #endif
  40. }
  41. AccessibilityHandler::AccessibilityHandler (Component& comp,
  42. AccessibilityRole accessibilityRole,
  43. AccessibilityActions accessibilityActions,
  44. Interfaces interfacesIn)
  45. : component (comp),
  46. typeIndex (typeid (component)),
  47. role (accessibilityRole),
  48. actions (std::move (accessibilityActions)),
  49. interfaces (std::move (interfacesIn)),
  50. nativeImpl (createNativeImpl (*this))
  51. {
  52. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::elementCreated);
  53. }
  54. AccessibilityHandler::~AccessibilityHandler()
  55. {
  56. giveAwayFocus();
  57. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::elementDestroyed);
  58. }
  59. //==============================================================================
  60. AccessibleState AccessibilityHandler::getCurrentState() const
  61. {
  62. if (component.isCurrentlyBlockedByAnotherModalComponent()
  63. && Component::getCurrentlyModalComponent()->isVisible())
  64. return {};
  65. auto state = AccessibleState().withFocusable();
  66. return hasFocus (false) ? state.withFocused() : state;
  67. }
  68. bool AccessibilityHandler::isIgnored() const
  69. {
  70. return role == AccessibilityRole::ignored || getCurrentState().isIgnored();
  71. }
  72. static bool isComponentVisibleWithinWindow (const Component& comp)
  73. {
  74. if (auto* peer = comp.getPeer())
  75. return ! peer->getAreaCoveredBy (comp).getIntersection (peer->getComponent().getLocalBounds()).isEmpty();
  76. return false;
  77. }
  78. static bool isComponentVisibleWithinParent (Component* comp)
  79. {
  80. if (auto* parent = comp->getParentComponent())
  81. {
  82. if (comp->getBoundsInParent().getIntersection (parent->getLocalBounds()).isEmpty())
  83. return false;
  84. return isComponentVisibleWithinParent (parent);
  85. }
  86. return true;
  87. }
  88. bool AccessibilityHandler::isVisibleWithinParent() const
  89. {
  90. return getCurrentState().isAccessibleOffscreen()
  91. || (isComponentVisibleWithinParent (&component) && isComponentVisibleWithinWindow (component));
  92. }
  93. //==============================================================================
  94. const AccessibilityActions& AccessibilityHandler::getActions() const noexcept
  95. {
  96. return actions;
  97. }
  98. AccessibilityValueInterface* AccessibilityHandler::getValueInterface() const
  99. {
  100. return interfaces.value.get();
  101. }
  102. AccessibilityTableInterface* AccessibilityHandler::getTableInterface() const
  103. {
  104. return interfaces.table.get();
  105. }
  106. AccessibilityCellInterface* AccessibilityHandler::getCellInterface() const
  107. {
  108. return interfaces.cell.get();
  109. }
  110. AccessibilityTextInterface* AccessibilityHandler::getTextInterface() const
  111. {
  112. return interfaces.text.get();
  113. }
  114. //==============================================================================
  115. static AccessibilityHandler* findEnclosingHandler (Component* comp)
  116. {
  117. if (comp != nullptr)
  118. {
  119. if (auto* handler = comp->getAccessibilityHandler())
  120. return handler;
  121. return findEnclosingHandler (comp->getParentComponent());
  122. }
  123. return nullptr;
  124. }
  125. static AccessibilityHandler* getUnignoredAncestor (AccessibilityHandler* handler)
  126. {
  127. while (handler != nullptr
  128. && (handler->isIgnored() || ! handler->isVisibleWithinParent())
  129. && handler->getParent() != nullptr)
  130. {
  131. handler = handler->getParent();
  132. }
  133. return handler;
  134. }
  135. static AccessibilityHandler* findFirstUnignoredChild (const std::vector<AccessibilityHandler*>& handlers)
  136. {
  137. if (! handlers.empty())
  138. {
  139. const auto iter = std::find_if (handlers.cbegin(), handlers.cend(),
  140. [] (const AccessibilityHandler* handler) { return ! handler->isIgnored() && handler->isVisibleWithinParent(); });
  141. if (iter != handlers.cend())
  142. return *iter;
  143. for (auto* handler : handlers)
  144. if (auto* unignored = findFirstUnignoredChild (handler->getChildren()))
  145. return unignored;
  146. }
  147. return nullptr;
  148. }
  149. static AccessibilityHandler* getFirstUnignoredDescendant (AccessibilityHandler* handler)
  150. {
  151. if (handler != nullptr && (handler->isIgnored() || ! handler->isVisibleWithinParent()))
  152. return findFirstUnignoredChild (handler->getChildren());
  153. return handler;
  154. }
  155. AccessibilityHandler* AccessibilityHandler::getParent() const
  156. {
  157. if (auto* focusContainer = component.findFocusContainer())
  158. return getUnignoredAncestor (findEnclosingHandler (focusContainer));
  159. return nullptr;
  160. }
  161. std::vector<AccessibilityHandler*> AccessibilityHandler::getChildren() const
  162. {
  163. if (! component.isFocusContainer() && component.getParentComponent() != nullptr)
  164. return {};
  165. const auto addChildComponentHandler = [this] (Component* focusableComponent,
  166. std::vector<AccessibilityHandler*>& childHandlers)
  167. {
  168. if (focusableComponent == nullptr)
  169. return;
  170. if (auto* handler = findEnclosingHandler (focusableComponent))
  171. {
  172. if (! handler->getCurrentState().isFocusable() || ! isParentOf (handler))
  173. return;
  174. if (auto* unignored = getFirstUnignoredDescendant (handler))
  175. if (std::find (childHandlers.cbegin(), childHandlers.cend(), unignored) == childHandlers.cend())
  176. childHandlers.push_back (unignored);
  177. }
  178. };
  179. std::vector<AccessibilityHandler*> children;
  180. if (auto traverser = component.createFocusTraverser())
  181. {
  182. addChildComponentHandler (traverser->getDefaultComponent (&component), children);
  183. for (auto* focusableChild : traverser->getAllComponents (&component))
  184. addChildComponentHandler (focusableChild, children);
  185. }
  186. return children;
  187. }
  188. bool AccessibilityHandler::isParentOf (const AccessibilityHandler* possibleChild) const noexcept
  189. {
  190. while (possibleChild != nullptr)
  191. {
  192. possibleChild = possibleChild->getParent();
  193. if (possibleChild == this)
  194. return true;
  195. }
  196. return false;
  197. }
  198. AccessibilityHandler* AccessibilityHandler::getChildAt (Point<int> screenPoint)
  199. {
  200. if (auto* comp = Desktop::getInstance().findComponentAt (screenPoint))
  201. {
  202. if (auto* handler = getUnignoredAncestor (findEnclosingHandler (comp)))
  203. if (isParentOf (handler))
  204. return handler;
  205. }
  206. return nullptr;
  207. }
  208. AccessibilityHandler* AccessibilityHandler::getChildFocus()
  209. {
  210. return hasFocus (true) ? getUnignoredAncestor (currentlyFocusedHandler)
  211. : nullptr;
  212. }
  213. bool AccessibilityHandler::hasFocus (bool trueIfChildFocused) const
  214. {
  215. return currentlyFocusedHandler != nullptr
  216. && (currentlyFocusedHandler == this
  217. || (trueIfChildFocused && isParentOf (currentlyFocusedHandler)));
  218. }
  219. void AccessibilityHandler::grabFocus()
  220. {
  221. if (! hasFocus (false))
  222. grabFocusInternal (true);
  223. }
  224. void AccessibilityHandler::giveAwayFocus() const
  225. {
  226. if (hasFocus (true))
  227. giveAwayFocusInternal();
  228. }
  229. void AccessibilityHandler::grabFocusInternal (bool canTryParent)
  230. {
  231. if (getCurrentState().isFocusable() && ! isIgnored())
  232. {
  233. takeFocus();
  234. return;
  235. }
  236. if (isParentOf (currentlyFocusedHandler))
  237. return;
  238. if (auto traverser = component.createFocusTraverser())
  239. {
  240. if (auto* defaultComp = traverser->getDefaultComponent (&component))
  241. {
  242. if (auto* handler = getUnignoredAncestor (findEnclosingHandler (defaultComp)))
  243. {
  244. if (isParentOf (handler))
  245. {
  246. handler->grabFocusInternal (false);
  247. return;
  248. }
  249. }
  250. }
  251. }
  252. if (canTryParent)
  253. if (auto* parent = getParent())
  254. parent->grabFocusInternal (true);
  255. }
  256. void AccessibilityHandler::giveAwayFocusInternal() const
  257. {
  258. currentlyFocusedHandler = nullptr;
  259. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::focusChanged);
  260. }
  261. void AccessibilityHandler::takeFocus()
  262. {
  263. currentlyFocusedHandler = this;
  264. notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::focusChanged);
  265. if ((component.isShowing() || component.isOnDesktop())
  266. && component.getWantsKeyboardFocus()
  267. && ! component.hasKeyboardFocus (true))
  268. {
  269. component.grabKeyboardFocus();
  270. }
  271. }
  272. } // namespace juce