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.

293 lines
7.3KB

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