Audio plugin host https://kx.studio/carla
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.

juce_ModalComponentManager.cpp 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  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 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. class ModalComponentManager::ModalItem : public ComponentMovementWatcher
  22. {
  23. public:
  24. ModalItem (Component* const comp, const bool autoDelete_)
  25. : ComponentMovementWatcher (comp),
  26. component (comp), returnValue (0),
  27. isActive (true), autoDelete (autoDelete_)
  28. {
  29. jassert (comp != nullptr);
  30. }
  31. void componentMovedOrResized (bool, bool) override {}
  32. void componentPeerChanged() override
  33. {
  34. if (! component->isShowing())
  35. cancel();
  36. }
  37. void componentVisibilityChanged() override
  38. {
  39. if (! component->isShowing())
  40. cancel();
  41. }
  42. void componentBeingDeleted (Component& comp) override
  43. {
  44. ComponentMovementWatcher::componentBeingDeleted (comp);
  45. if (component == &comp || comp.isParentOf (component))
  46. {
  47. autoDelete = false;
  48. cancel();
  49. }
  50. }
  51. void cancel()
  52. {
  53. if (isActive)
  54. {
  55. isActive = false;
  56. if (ModalComponentManager* mcm = ModalComponentManager::getInstanceWithoutCreating())
  57. mcm->triggerAsyncUpdate();
  58. }
  59. }
  60. Component* component;
  61. OwnedArray<Callback> callbacks;
  62. int returnValue;
  63. bool isActive, autoDelete;
  64. private:
  65. JUCE_DECLARE_NON_COPYABLE (ModalItem)
  66. };
  67. //==============================================================================
  68. ModalComponentManager::ModalComponentManager()
  69. {
  70. }
  71. ModalComponentManager::~ModalComponentManager()
  72. {
  73. stack.clear();
  74. clearSingletonInstance();
  75. }
  76. juce_ImplementSingleton_SingleThreaded (ModalComponentManager)
  77. //==============================================================================
  78. void ModalComponentManager::startModal (Component* component, bool autoDelete)
  79. {
  80. if (component != nullptr)
  81. stack.add (new ModalItem (component, autoDelete));
  82. }
  83. void ModalComponentManager::attachCallback (Component* component, Callback* callback)
  84. {
  85. if (callback != nullptr)
  86. {
  87. ScopedPointer<Callback> callbackDeleter (callback);
  88. for (int i = stack.size(); --i >= 0;)
  89. {
  90. ModalItem* const item = stack.getUnchecked(i);
  91. if (item->component == component)
  92. {
  93. item->callbacks.add (callback);
  94. callbackDeleter.release();
  95. break;
  96. }
  97. }
  98. }
  99. }
  100. void ModalComponentManager::endModal (Component* component)
  101. {
  102. for (int i = stack.size(); --i >= 0;)
  103. {
  104. ModalItem* const item = stack.getUnchecked(i);
  105. if (item->component == component)
  106. item->cancel();
  107. }
  108. }
  109. void ModalComponentManager::endModal (Component* component, int returnValue)
  110. {
  111. for (int i = stack.size(); --i >= 0;)
  112. {
  113. ModalItem* const item = stack.getUnchecked(i);
  114. if (item->component == component)
  115. {
  116. item->returnValue = returnValue;
  117. item->cancel();
  118. }
  119. }
  120. }
  121. int ModalComponentManager::getNumModalComponents() const
  122. {
  123. int n = 0;
  124. for (int i = 0; i < stack.size(); ++i)
  125. if (stack.getUnchecked(i)->isActive)
  126. ++n;
  127. return n;
  128. }
  129. Component* ModalComponentManager::getModalComponent (const int index) const
  130. {
  131. int n = 0;
  132. for (int i = stack.size(); --i >= 0;)
  133. {
  134. const ModalItem* const item = stack.getUnchecked(i);
  135. if (item->isActive)
  136. if (n++ == index)
  137. return item->component;
  138. }
  139. return nullptr;
  140. }
  141. bool ModalComponentManager::isModal (Component* const comp) const
  142. {
  143. for (int i = stack.size(); --i >= 0;)
  144. {
  145. const ModalItem* const item = stack.getUnchecked(i);
  146. if (item->isActive && item->component == comp)
  147. return true;
  148. }
  149. return false;
  150. }
  151. bool ModalComponentManager::isFrontModalComponent (Component* const comp) const
  152. {
  153. return comp == getModalComponent (0);
  154. }
  155. void ModalComponentManager::handleAsyncUpdate()
  156. {
  157. for (int i = stack.size(); --i >= 0;)
  158. {
  159. const ModalItem* const item = stack.getUnchecked(i);
  160. if (! item->isActive)
  161. {
  162. ScopedPointer<ModalItem> deleter (stack.removeAndReturn (i));
  163. Component::SafePointer<Component> compToDelete (item->autoDelete ? item->component : nullptr);
  164. for (int j = item->callbacks.size(); --j >= 0;)
  165. item->callbacks.getUnchecked(j)->modalStateFinished (item->returnValue);
  166. compToDelete.deleteAndZero();
  167. }
  168. }
  169. }
  170. void ModalComponentManager::bringModalComponentsToFront (bool topOneShouldGrabFocus)
  171. {
  172. ComponentPeer* lastOne = nullptr;
  173. for (int i = 0; i < getNumModalComponents(); ++i)
  174. {
  175. Component* const c = getModalComponent (i);
  176. if (c == nullptr)
  177. break;
  178. ComponentPeer* peer = c->getPeer();
  179. if (peer != nullptr && peer != lastOne)
  180. {
  181. if (lastOne == nullptr)
  182. {
  183. peer->toFront (topOneShouldGrabFocus);
  184. if (topOneShouldGrabFocus)
  185. peer->grabFocus();
  186. }
  187. else
  188. peer->toBehind (lastOne);
  189. lastOne = peer;
  190. }
  191. }
  192. }
  193. bool ModalComponentManager::cancelAllModalComponents()
  194. {
  195. const int numModal = getNumModalComponents();
  196. for (int i = numModal; --i >= 0;)
  197. if (Component* const c = getModalComponent(i))
  198. c->exitModalState (0);
  199. return numModal > 0;
  200. }
  201. //==============================================================================
  202. #if JUCE_MODAL_LOOPS_PERMITTED
  203. class ModalComponentManager::ReturnValueRetriever : public ModalComponentManager::Callback
  204. {
  205. public:
  206. ReturnValueRetriever (int& v, bool& done) : value (v), finished (done) {}
  207. void modalStateFinished (int returnValue) override
  208. {
  209. finished = true;
  210. value = returnValue;
  211. }
  212. private:
  213. int& value;
  214. bool& finished;
  215. JUCE_DECLARE_NON_COPYABLE (ReturnValueRetriever)
  216. };
  217. int ModalComponentManager::runEventLoopForCurrentComponent()
  218. {
  219. // This can only be run from the message thread!
  220. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  221. int returnValue = 0;
  222. if (Component* currentlyModal = getModalComponent (0))
  223. {
  224. FocusRestorer focusRestorer;
  225. bool finished = false;
  226. attachCallback (currentlyModal, new ReturnValueRetriever (returnValue, finished));
  227. JUCE_TRY
  228. {
  229. while (! finished)
  230. {
  231. if (! MessageManager::getInstance()->runDispatchLoopUntil (20))
  232. break;
  233. }
  234. }
  235. JUCE_CATCH_EXCEPTION
  236. }
  237. return returnValue;
  238. }
  239. #endif
  240. //==============================================================================
  241. struct LambdaCallback : public ModalComponentManager::Callback
  242. {
  243. LambdaCallback (std::function<void(int)> fn) noexcept : function (fn) {}
  244. void modalStateFinished (int result) override { function (result); }
  245. std::function<void(int)> function;
  246. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LambdaCallback)
  247. };
  248. ModalComponentManager::Callback* ModalCallbackFunction::create (std::function<void(int)> f)
  249. {
  250. return new LambdaCallback (f);
  251. }
  252. } // namespace juce