The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

286 lines
7.6KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. class ModalComponentManager::ModalItem : public ComponentMovementWatcher
  19. {
  20. public:
  21. ModalItem (Component* const comp, const bool autoDelete_)
  22. : ComponentMovementWatcher (comp),
  23. component (comp), returnValue (0),
  24. isActive (true), autoDelete (autoDelete_)
  25. {
  26. jassert (comp != nullptr);
  27. }
  28. void componentMovedOrResized (bool, bool) {}
  29. void componentPeerChanged()
  30. {
  31. if (! component->isShowing())
  32. cancel();
  33. }
  34. void componentVisibilityChanged()
  35. {
  36. if (! component->isShowing())
  37. cancel();
  38. }
  39. void componentBeingDeleted (Component& comp)
  40. {
  41. ComponentMovementWatcher::componentBeingDeleted (comp);
  42. if (component == &comp || comp.isParentOf (component))
  43. {
  44. autoDelete = false;
  45. cancel();
  46. }
  47. }
  48. void cancel()
  49. {
  50. if (isActive)
  51. {
  52. isActive = false;
  53. ModalComponentManager::getInstance()->triggerAsyncUpdate();
  54. }
  55. }
  56. Component* component;
  57. OwnedArray<Callback> callbacks;
  58. int returnValue;
  59. bool isActive, autoDelete;
  60. private:
  61. JUCE_DECLARE_NON_COPYABLE (ModalItem);
  62. };
  63. //==============================================================================
  64. ModalComponentManager::ModalComponentManager()
  65. {
  66. }
  67. ModalComponentManager::~ModalComponentManager()
  68. {
  69. clearSingletonInstance();
  70. }
  71. juce_ImplementSingleton_SingleThreaded (ModalComponentManager);
  72. //==============================================================================
  73. void ModalComponentManager::startModal (Component* component, bool autoDelete)
  74. {
  75. if (component != nullptr)
  76. stack.add (new ModalItem (component, autoDelete));
  77. }
  78. void ModalComponentManager::attachCallback (Component* component, Callback* callback)
  79. {
  80. if (callback != nullptr)
  81. {
  82. ScopedPointer<Callback> callbackDeleter (callback);
  83. for (int i = stack.size(); --i >= 0;)
  84. {
  85. ModalItem* const item = stack.getUnchecked(i);
  86. if (item->component == component)
  87. {
  88. item->callbacks.add (callback);
  89. callbackDeleter.release();
  90. break;
  91. }
  92. }
  93. }
  94. }
  95. void ModalComponentManager::endModal (Component* component)
  96. {
  97. for (int i = stack.size(); --i >= 0;)
  98. {
  99. ModalItem* const item = stack.getUnchecked(i);
  100. if (item->component == component)
  101. item->cancel();
  102. }
  103. }
  104. void ModalComponentManager::endModal (Component* component, int returnValue)
  105. {
  106. for (int i = stack.size(); --i >= 0;)
  107. {
  108. ModalItem* const item = stack.getUnchecked(i);
  109. if (item->component == component)
  110. {
  111. item->returnValue = returnValue;
  112. item->cancel();
  113. }
  114. }
  115. }
  116. int ModalComponentManager::getNumModalComponents() const
  117. {
  118. int n = 0;
  119. for (int i = 0; i < stack.size(); ++i)
  120. if (stack.getUnchecked(i)->isActive)
  121. ++n;
  122. return n;
  123. }
  124. Component* ModalComponentManager::getModalComponent (const int index) const
  125. {
  126. int n = 0;
  127. for (int i = stack.size(); --i >= 0;)
  128. {
  129. const ModalItem* const item = stack.getUnchecked(i);
  130. if (item->isActive)
  131. if (n++ == index)
  132. return item->component;
  133. }
  134. return nullptr;
  135. }
  136. bool ModalComponentManager::isModal (Component* const comp) const
  137. {
  138. for (int i = stack.size(); --i >= 0;)
  139. {
  140. const ModalItem* const item = stack.getUnchecked(i);
  141. if (item->isActive && item->component == comp)
  142. return true;
  143. }
  144. return false;
  145. }
  146. bool ModalComponentManager::isFrontModalComponent (Component* const comp) const
  147. {
  148. return comp == getModalComponent (0);
  149. }
  150. void ModalComponentManager::handleAsyncUpdate()
  151. {
  152. for (int i = stack.size(); --i >= 0;)
  153. {
  154. const ModalItem* const item = stack.getUnchecked(i);
  155. if (! item->isActive)
  156. {
  157. ScopedPointer<ModalItem> deleter (stack.removeAndReturn (i));
  158. Component::SafePointer<Component> compToDelete (item->autoDelete ? item->component : nullptr);
  159. for (int j = item->callbacks.size(); --j >= 0;)
  160. item->callbacks.getUnchecked(j)->modalStateFinished (item->returnValue);
  161. compToDelete.deleteAndZero();
  162. }
  163. }
  164. }
  165. void ModalComponentManager::bringModalComponentsToFront (bool topOneShouldGrabFocus)
  166. {
  167. ComponentPeer* lastOne = nullptr;
  168. for (int i = 0; i < getNumModalComponents(); ++i)
  169. {
  170. Component* const c = getModalComponent (i);
  171. if (c == nullptr)
  172. break;
  173. ComponentPeer* peer = c->getPeer();
  174. if (peer != nullptr && peer != lastOne)
  175. {
  176. if (lastOne == nullptr)
  177. {
  178. peer->toFront (topOneShouldGrabFocus);
  179. if (topOneShouldGrabFocus)
  180. peer->grabFocus();
  181. }
  182. else
  183. peer->toBehind (lastOne);
  184. lastOne = peer;
  185. }
  186. }
  187. }
  188. #if JUCE_MODAL_LOOPS_PERMITTED
  189. class ModalComponentManager::ReturnValueRetriever : public ModalComponentManager::Callback
  190. {
  191. public:
  192. ReturnValueRetriever (int& value_, bool& finished_) : value (value_), finished (finished_) {}
  193. void modalStateFinished (int returnValue)
  194. {
  195. finished = true;
  196. value = returnValue;
  197. }
  198. private:
  199. int& value;
  200. bool& finished;
  201. JUCE_DECLARE_NON_COPYABLE (ReturnValueRetriever);
  202. };
  203. int ModalComponentManager::runEventLoopForCurrentComponent()
  204. {
  205. // This can only be run from the message thread!
  206. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  207. Component* currentlyModal = getModalComponent (0);
  208. if (currentlyModal == nullptr)
  209. return 0;
  210. WeakReference<Component> prevFocused (Component::getCurrentlyFocusedComponent());
  211. int returnValue = 0;
  212. bool finished = false;
  213. attachCallback (currentlyModal, new ReturnValueRetriever (returnValue, finished));
  214. JUCE_TRY
  215. {
  216. while (! finished)
  217. {
  218. if (! MessageManager::getInstance()->runDispatchLoopUntil (20))
  219. break;
  220. }
  221. }
  222. JUCE_CATCH_EXCEPTION
  223. if (prevFocused != nullptr)
  224. prevFocused->grabKeyboardFocus();
  225. return returnValue;
  226. }
  227. #endif