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.

284 lines
7.4KB

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