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.

308 lines
7.8KB

  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. struct ModalComponentManager::ModalItem : public ComponentMovementWatcher
  21. {
  22. ModalItem (Component* comp, bool shouldAutoDelete)
  23. : ComponentMovementWatcher (comp),
  24. component (comp), autoDelete (shouldAutoDelete)
  25. {
  26. jassert (comp != nullptr);
  27. }
  28. void componentMovedOrResized (bool, bool) override {}
  29. using ComponentMovementWatcher::componentMovedOrResized;
  30. void componentPeerChanged() override
  31. {
  32. componentVisibilityChanged();
  33. }
  34. void componentVisibilityChanged() override
  35. {
  36. if (! component->isShowing())
  37. cancel();
  38. }
  39. using ComponentMovementWatcher::componentVisibilityChanged;
  40. void componentBeingDeleted (Component& comp) override
  41. {
  42. ComponentMovementWatcher::componentBeingDeleted (comp);
  43. if (component == &comp || comp.isParentOf (component))
  44. {
  45. autoDelete = false;
  46. cancel();
  47. }
  48. }
  49. void cancel()
  50. {
  51. if (isActive)
  52. {
  53. isActive = false;
  54. if (auto* mcm = ModalComponentManager::getInstanceWithoutCreating())
  55. mcm->triggerAsyncUpdate();
  56. }
  57. }
  58. Component* component;
  59. OwnedArray<Callback> callbacks;
  60. int returnValue = 0;
  61. bool isActive = true, autoDelete;
  62. JUCE_DECLARE_NON_COPYABLE (ModalItem)
  63. };
  64. //==============================================================================
  65. ModalComponentManager::ModalComponentManager()
  66. {
  67. }
  68. ModalComponentManager::~ModalComponentManager()
  69. {
  70. stack.clear();
  71. clearSingletonInstance();
  72. }
  73. JUCE_IMPLEMENT_SINGLETON (ModalComponentManager)
  74. //==============================================================================
  75. void ModalComponentManager::startModal (Component* component, bool autoDelete)
  76. {
  77. if (component != nullptr)
  78. stack.add (new ModalItem (component, autoDelete));
  79. }
  80. void ModalComponentManager::attachCallback (Component* component, Callback* callback)
  81. {
  82. if (callback != nullptr)
  83. {
  84. std::unique_ptr<Callback> callbackDeleter (callback);
  85. for (int i = stack.size(); --i >= 0;)
  86. {
  87. auto* item = stack.getUnchecked(i);
  88. if (item->component == component)
  89. {
  90. item->callbacks.add (callback);
  91. callbackDeleter.release();
  92. break;
  93. }
  94. }
  95. }
  96. }
  97. void ModalComponentManager::endModal (Component* component)
  98. {
  99. for (int i = stack.size(); --i >= 0;)
  100. {
  101. auto* item = stack.getUnchecked(i);
  102. if (item->component == component)
  103. item->cancel();
  104. }
  105. }
  106. void ModalComponentManager::endModal (Component* component, int returnValue)
  107. {
  108. for (int i = stack.size(); --i >= 0;)
  109. {
  110. auto* item = stack.getUnchecked(i);
  111. if (item->component == component)
  112. {
  113. item->returnValue = returnValue;
  114. item->cancel();
  115. }
  116. }
  117. }
  118. int ModalComponentManager::getNumModalComponents() const
  119. {
  120. int n = 0;
  121. for (auto* item : stack)
  122. if (item->isActive)
  123. ++n;
  124. return n;
  125. }
  126. Component* ModalComponentManager::getModalComponent (int index) const
  127. {
  128. int n = 0;
  129. for (int i = stack.size(); --i >= 0;)
  130. {
  131. auto* item = stack.getUnchecked(i);
  132. if (item->isActive)
  133. if (n++ == index)
  134. return item->component;
  135. }
  136. return nullptr;
  137. }
  138. bool ModalComponentManager::isModal (const Component* comp) const
  139. {
  140. for (auto* item : stack)
  141. if (item->isActive && item->component == comp)
  142. return true;
  143. return false;
  144. }
  145. bool ModalComponentManager::isFrontModalComponent (const Component* comp) const
  146. {
  147. return comp == getModalComponent (0);
  148. }
  149. void ModalComponentManager::handleAsyncUpdate()
  150. {
  151. for (int i = stack.size(); --i >= 0;)
  152. {
  153. auto* item = stack.getUnchecked(i);
  154. if (! item->isActive)
  155. {
  156. std::unique_ptr<ModalItem> deleter (stack.removeAndReturn (i));
  157. Component::SafePointer<Component> compToDelete (item->autoDelete ? item->component : nullptr);
  158. for (int j = item->callbacks.size(); --j >= 0;)
  159. item->callbacks.getUnchecked(j)->modalStateFinished (item->returnValue);
  160. compToDelete.deleteAndZero();
  161. }
  162. }
  163. }
  164. void ModalComponentManager::bringModalComponentsToFront (bool topOneShouldGrabFocus)
  165. {
  166. ComponentPeer* lastOne = nullptr;
  167. for (int i = 0; i < getNumModalComponents(); ++i)
  168. {
  169. auto* c = getModalComponent (i);
  170. if (c == nullptr)
  171. break;
  172. if (auto* peer = c->getPeer())
  173. {
  174. if (peer != lastOne)
  175. {
  176. if (lastOne == nullptr)
  177. {
  178. peer->toFront (topOneShouldGrabFocus);
  179. if (topOneShouldGrabFocus)
  180. peer->grabFocus();
  181. }
  182. else
  183. {
  184. peer->toBehind (lastOne);
  185. }
  186. lastOne = peer;
  187. }
  188. }
  189. }
  190. }
  191. bool ModalComponentManager::cancelAllModalComponents()
  192. {
  193. auto numModal = getNumModalComponents();
  194. for (int i = numModal; --i >= 0;)
  195. if (auto* c = getModalComponent(i))
  196. c->exitModalState (0);
  197. return numModal > 0;
  198. }
  199. //==============================================================================
  200. #if JUCE_MODAL_LOOPS_PERMITTED
  201. int ModalComponentManager::runEventLoopForCurrentComponent()
  202. {
  203. // This can only be run from the message thread!
  204. JUCE_ASSERT_MESSAGE_THREAD
  205. int returnValue = 0;
  206. if (auto* currentlyModal = getModalComponent (0))
  207. {
  208. FocusRestorer focusRestorer;
  209. bool finished = false;
  210. attachCallback (currentlyModal, ModalCallbackFunction::create ([&] (int r) { returnValue = r; finished = true; }));
  211. JUCE_TRY
  212. {
  213. while (! finished)
  214. {
  215. if (! MessageManager::getInstance()->runDispatchLoopUntil (20))
  216. break;
  217. }
  218. }
  219. JUCE_CATCH_EXCEPTION
  220. }
  221. return returnValue;
  222. }
  223. #endif
  224. //==============================================================================
  225. struct LambdaCallback : public ModalComponentManager::Callback
  226. {
  227. LambdaCallback (std::function<void (int)> fn) noexcept : function (fn) {}
  228. void modalStateFinished (int result) override
  229. {
  230. if (function != nullptr)
  231. function (result);
  232. }
  233. std::function<void (int)> function;
  234. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LambdaCallback)
  235. };
  236. ModalComponentManager::Callback* ModalCallbackFunction::create (std::function<void (int)> f)
  237. {
  238. return new LambdaCallback (f);
  239. }
  240. } // namespace juce