123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- /*
- ==============================================================================
- This file is part of the JUCE library.
- Copyright (c) 2017 - ROLI Ltd.
- 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 5 End-User License
- Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
- 27th April 2017).
- End User License Agreement: www.juce.com/juce-5-licence
- Privacy Policy: www.juce.com/juce-5-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
- {
- struct ModalComponentManager::ModalItem : public ComponentMovementWatcher
- {
- ModalItem (Component* comp, bool shouldAutoDelete)
- : ComponentMovementWatcher (comp),
- component (comp), autoDelete (shouldAutoDelete)
- {
- jassert (comp != nullptr);
- }
- void componentMovedOrResized (bool, bool) override {}
- using ComponentMovementWatcher::componentMovedOrResized;
- void componentPeerChanged() override
- {
- componentVisibilityChanged();
- }
- void componentVisibilityChanged() override
- {
- if (! component->isShowing())
- cancel();
- }
- using ComponentMovementWatcher::componentVisibilityChanged;
- void componentBeingDeleted (Component& comp) override
- {
- ComponentMovementWatcher::componentBeingDeleted (comp);
- if (component == &comp || comp.isParentOf (component))
- {
- autoDelete = false;
- cancel();
- }
- }
- void cancel()
- {
- if (isActive)
- {
- isActive = false;
- if (auto* mcm = ModalComponentManager::getInstanceWithoutCreating())
- mcm->triggerAsyncUpdate();
- }
- }
- Component* component;
- OwnedArray<Callback> callbacks;
- int returnValue = 0;
- bool isActive = true, autoDelete;
- JUCE_DECLARE_NON_COPYABLE (ModalItem)
- };
- //==============================================================================
- ModalComponentManager::ModalComponentManager()
- {
- }
- ModalComponentManager::~ModalComponentManager()
- {
- stack.clear();
- clearSingletonInstance();
- }
- JUCE_IMPLEMENT_SINGLETON (ModalComponentManager)
- //==============================================================================
- void ModalComponentManager::startModal (Component* component, bool autoDelete)
- {
- if (component != nullptr)
- stack.add (new ModalItem (component, autoDelete));
- }
- void ModalComponentManager::attachCallback (Component* component, Callback* callback)
- {
- if (callback != nullptr)
- {
- std::unique_ptr<Callback> callbackDeleter (callback);
- for (int i = stack.size(); --i >= 0;)
- {
- auto* item = stack.getUnchecked(i);
- if (item->component == component)
- {
- item->callbacks.add (callback);
- callbackDeleter.release();
- break;
- }
- }
- }
- }
- void ModalComponentManager::endModal (Component* component)
- {
- for (int i = stack.size(); --i >= 0;)
- {
- auto* item = stack.getUnchecked(i);
- if (item->component == component)
- item->cancel();
- }
- }
- void ModalComponentManager::endModal (Component* component, int returnValue)
- {
- for (int i = stack.size(); --i >= 0;)
- {
- auto* item = stack.getUnchecked(i);
- if (item->component == component)
- {
- item->returnValue = returnValue;
- item->cancel();
- }
- }
- }
- int ModalComponentManager::getNumModalComponents() const
- {
- int n = 0;
- for (auto* item : stack)
- if (item->isActive)
- ++n;
- return n;
- }
- Component* ModalComponentManager::getModalComponent (int index) const
- {
- int n = 0;
- for (int i = stack.size(); --i >= 0;)
- {
- auto* item = stack.getUnchecked(i);
- if (item->isActive)
- if (n++ == index)
- return item->component;
- }
- return nullptr;
- }
- bool ModalComponentManager::isModal (const Component* comp) const
- {
- for (auto* item : stack)
- if (item->isActive && item->component == comp)
- return true;
- return false;
- }
- bool ModalComponentManager::isFrontModalComponent (const Component* comp) const
- {
- return comp == getModalComponent (0);
- }
- void ModalComponentManager::handleAsyncUpdate()
- {
- for (int i = stack.size(); --i >= 0;)
- {
- auto* item = stack.getUnchecked(i);
- if (! item->isActive)
- {
- std::unique_ptr<ModalItem> deleter (stack.removeAndReturn (i));
- Component::SafePointer<Component> compToDelete (item->autoDelete ? item->component : nullptr);
- for (int j = item->callbacks.size(); --j >= 0;)
- item->callbacks.getUnchecked(j)->modalStateFinished (item->returnValue);
- compToDelete.deleteAndZero();
- }
- }
- }
- void ModalComponentManager::bringModalComponentsToFront (bool topOneShouldGrabFocus)
- {
- ComponentPeer* lastOne = nullptr;
- for (int i = 0; i < getNumModalComponents(); ++i)
- {
- auto* c = getModalComponent (i);
- if (c == nullptr)
- break;
- if (auto* peer = c->getPeer())
- {
- if (peer != lastOne)
- {
- if (lastOne == nullptr)
- {
- peer->toFront (topOneShouldGrabFocus);
- if (topOneShouldGrabFocus)
- peer->grabFocus();
- }
- else
- {
- peer->toBehind (lastOne);
- }
- lastOne = peer;
- }
- }
- }
- }
- bool ModalComponentManager::cancelAllModalComponents()
- {
- auto numModal = getNumModalComponents();
- for (int i = numModal; --i >= 0;)
- if (auto* c = getModalComponent(i))
- c->exitModalState (0);
- return numModal > 0;
- }
- //==============================================================================
- #if JUCE_MODAL_LOOPS_PERMITTED
- int ModalComponentManager::runEventLoopForCurrentComponent()
- {
- // This can only be run from the message thread!
- JUCE_ASSERT_MESSAGE_THREAD
- int returnValue = 0;
- if (auto* currentlyModal = getModalComponent (0))
- {
- FocusRestorer focusRestorer;
- bool finished = false;
- attachCallback (currentlyModal, ModalCallbackFunction::create ([&] (int r) { returnValue = r; finished = true; }));
- JUCE_TRY
- {
- while (! finished)
- {
- if (! MessageManager::getInstance()->runDispatchLoopUntil (20))
- break;
- }
- }
- JUCE_CATCH_EXCEPTION
- }
- return returnValue;
- }
- #endif
- //==============================================================================
- struct LambdaCallback : public ModalComponentManager::Callback
- {
- LambdaCallback (std::function<void(int)> fn) noexcept : function (fn) {}
- void modalStateFinished (int result) override
- {
- if (function != nullptr)
- function (result);
- }
- std::function<void(int)> function;
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LambdaCallback)
- };
- ModalComponentManager::Callback* ModalCallbackFunction::create (std::function<void(int)> f)
- {
- return new LambdaCallback (f);
- }
- } // namespace juce
|