|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2020 - Raw Material Software Limited
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- By using JUCE, you agree to the terms of both the JUCE 6 End-User License
- Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
-
- End User License Agreement: www.juce.com/juce-6-licence
- Privacy Policy: www.juce.com/juce-privacy-policy
-
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
-
- AccessibilityHandler* AccessibilityHandler::currentlyFocusedHandler = nullptr;
-
- enum class InternalAccessibilityEvent
- {
- elementCreated,
- elementDestroyed,
- focusChanged,
- windowOpened,
- windowClosed
- };
-
- void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, InternalAccessibilityEvent event);
-
- inline String getAccessibleApplicationOrPluginName()
- {
- #if defined (JucePlugin_Name)
- return JucePlugin_Name;
- #else
- if (auto* app = JUCEApplicationBase::getInstance())
- return app->getApplicationName();
-
- return "JUCE Application";
- #endif
- }
-
- AccessibilityHandler::AccessibilityHandler (Component& comp,
- AccessibilityRole accessibilityRole,
- AccessibilityActions accessibilityActions,
- Interfaces interfacesIn)
- : component (comp),
- typeIndex (typeid (component)),
- role (accessibilityRole),
- actions (std::move (accessibilityActions)),
- interfaces (std::move (interfacesIn)),
- nativeImpl (createNativeImpl (*this))
- {
- notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::elementCreated);
- }
-
- AccessibilityHandler::~AccessibilityHandler()
- {
- giveAwayFocus();
- notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::elementDestroyed);
- }
-
- //==============================================================================
- AccessibleState AccessibilityHandler::getCurrentState() const
- {
- auto state = AccessibleState().withFocusable();
-
- return hasFocus (false) ? state.withFocused() : state;
- }
-
- static bool isComponentVisibleWithinWindow (const Component& comp)
- {
- if (auto* peer = comp.getPeer())
- return ! peer->getAreaCoveredBy (comp).getIntersection (peer->getComponent().getLocalBounds()).isEmpty();
-
- return false;
- }
-
- static bool isComponentVisibleWithinParent (Component* comp)
- {
- if (auto* parent = comp->getParentComponent())
- {
- if (comp->getBoundsInParent().getIntersection (parent->getLocalBounds()).isEmpty())
- return false;
-
- return isComponentVisibleWithinParent (parent);
- }
-
- return true;
- }
-
- bool AccessibilityHandler::isIgnored() const
- {
- const auto state = getCurrentState();
-
- return role == AccessibilityRole::ignored
- || state.isIgnored()
- || ! component.isShowing()
- || (! state.isAccessibleOffscreen()
- && (! isComponentVisibleWithinParent (&component)
- || ! isComponentVisibleWithinWindow (component)));
- }
-
- //==============================================================================
- const AccessibilityActions& AccessibilityHandler::getActions() const noexcept
- {
- return actions;
- }
-
- AccessibilityValueInterface* AccessibilityHandler::getValueInterface() const
- {
- return interfaces.value.get();
- }
-
- AccessibilityTableInterface* AccessibilityHandler::getTableInterface() const
- {
- return interfaces.table.get();
- }
-
- AccessibilityCellInterface* AccessibilityHandler::getCellInterface() const
- {
- return interfaces.cell.get();
- }
-
- AccessibilityTextInterface* AccessibilityHandler::getTextInterface() const
- {
- return interfaces.text.get();
- }
-
- //==============================================================================
- static AccessibilityHandler* findEnclosingHandler (Component* comp)
- {
- if (comp != nullptr)
- {
- if (auto* handler = comp->getAccessibilityHandler())
- return handler;
-
- return findEnclosingHandler (comp->getParentComponent());
- }
-
- return nullptr;
- }
-
- static AccessibilityHandler* getUnignoredAncestor (AccessibilityHandler* handler)
- {
- while (handler != nullptr
- && handler->isIgnored()
- && handler->getParent() != nullptr)
- {
- handler = handler->getParent();
- }
-
- return handler;
- }
-
- static AccessibilityHandler* findFirstUnignoredChild (const std::vector<AccessibilityHandler*>& handlers)
- {
- if (! handlers.empty())
- {
- const auto iter = std::find_if (handlers.cbegin(), handlers.cend(),
- [] (const AccessibilityHandler* handler) { return ! handler->isIgnored(); });
-
- if (iter != handlers.cend())
- return *iter;
-
- for (auto* handler : handlers)
- if (auto* unignored = findFirstUnignoredChild (handler->getChildren()))
- return unignored;
- }
-
- return nullptr;
- }
-
- static AccessibilityHandler* getFirstUnignoredDescendant (AccessibilityHandler* handler)
- {
- if (handler != nullptr && handler->isIgnored())
- return findFirstUnignoredChild (handler->getChildren());
-
- return handler;
- }
-
- AccessibilityHandler* AccessibilityHandler::getParent() const
- {
- if (auto* focusContainer = component.findFocusContainer())
- return getUnignoredAncestor (findEnclosingHandler (focusContainer));
-
- return nullptr;
- }
-
- std::vector<AccessibilityHandler*> AccessibilityHandler::getChildren() const
- {
- if (! component.isFocusContainer() && component.getParentComponent() != nullptr)
- return {};
-
- std::vector<AccessibilityHandler*> children;
-
- if (auto traverser = component.createFocusTraverser())
- {
- for (auto* focusableChild : traverser->getAllComponents (&component))
- {
- if (auto* handler = findEnclosingHandler (focusableChild))
- {
- if (! isParentOf (handler))
- continue;
-
- if (auto* unignored = getFirstUnignoredDescendant (handler))
- if (std::find (children.cbegin(), children.cend(), unignored) == children.cend())
- children.push_back (unignored);
- }
- }
- }
-
- return children;
- }
-
- bool AccessibilityHandler::isParentOf (const AccessibilityHandler* possibleChild) const noexcept
- {
- while (possibleChild != nullptr)
- {
- possibleChild = possibleChild->getParent();
-
- if (possibleChild == this)
- return true;
- }
-
- return false;
- }
-
- AccessibilityHandler* AccessibilityHandler::getChildAt (Point<int> screenPoint)
- {
- if (auto* comp = Desktop::getInstance().findComponentAt (screenPoint))
- if (isParentOf (comp->getAccessibilityHandler()))
- return getUnignoredAncestor (findEnclosingHandler (comp));
-
- return nullptr;
- }
-
- AccessibilityHandler* AccessibilityHandler::getChildFocus()
- {
- return hasFocus (true) ? getUnignoredAncestor (currentlyFocusedHandler)
- : nullptr;
- }
-
- bool AccessibilityHandler::hasFocus (bool trueIfChildFocused) const
- {
- return currentlyFocusedHandler != nullptr
- && (currentlyFocusedHandler == this
- || (trueIfChildFocused && isParentOf (currentlyFocusedHandler)));
- }
-
- void AccessibilityHandler::grabFocus()
- {
- if (! hasFocus (false))
- grabFocusInternal (true);
- }
-
- void AccessibilityHandler::giveAwayFocus() const
- {
- if (hasFocus (true))
- giveAwayFocusInternal();
- }
-
- void AccessibilityHandler::grabFocusInternal (bool canTryParent)
- {
- if (getCurrentState().isFocusable() && ! isIgnored())
- {
- takeFocus();
- return;
- }
-
- if (isParentOf (currentlyFocusedHandler) && ! currentlyFocusedHandler->isIgnored())
- return;
-
- if (component.isFocusContainer() || component.getParentComponent() == nullptr)
- {
- if (auto traverser = component.createFocusTraverser())
- {
- if (auto* defaultComp = traverser->getDefaultComponent (&component))
- {
- if (auto* handler = getUnignoredAncestor (findEnclosingHandler (defaultComp)))
- {
- if (isParentOf (handler))
- {
- handler->grabFocusInternal (false);
- return;
- }
- }
- }
- }
- }
-
- if (canTryParent)
- if (auto* parent = getParent())
- parent->grabFocusInternal (true);
- }
-
- void AccessibilityHandler::giveAwayFocusInternal() const
- {
- currentlyFocusedHandler = nullptr;
- notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::focusChanged);
-
- if (auto* focusedComponent = Component::getCurrentlyFocusedComponent())
- if (auto* handler = focusedComponent->getAccessibilityHandler())
- handler->grabFocus();
- }
-
- void AccessibilityHandler::takeFocus()
- {
- currentlyFocusedHandler = this;
-
- WeakReference<Component> weakComponent (&component);
- actions.invoke (AccessibilityActionType::focus);
-
- if (weakComponent != nullptr
- && component.getWantsKeyboardFocus()
- && ! component.hasKeyboardFocus (true))
- {
- component.grabKeyboardFocus();
- }
-
- notifyAccessibilityEventInternal (*this, InternalAccessibilityEvent::focusChanged);
- }
-
- //==============================================================================
- #if ! (JUCE_MAC || (JUCE_WINDOWS && ! JUCE_MINGW))
- class AccessibilityHandler::AccessibilityNativeImpl { public: AccessibilityNativeImpl (AccessibilityHandler&) {} };
- void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent) const {}
- void AccessibilityHandler::postAnnouncement (const String&, AnnouncementPriority) {}
- AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const { return nullptr; }
- AccessibilityHandler::AccessibilityNativeImpl* AccessibilityHandler::createNativeImpl (AccessibilityHandler&) { return nullptr; }
- void AccessibilityHandler::DestroyNativeImpl::operator() (AccessibilityHandler::AccessibilityNativeImpl*) const noexcept {}
- void notifyAccessibilityEventInternal (const AccessibilityHandler&, InternalAccessibilityEvent) {}
- #endif
-
- } // namespace juce
|