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.

291 lines
7.7KB

  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, const bool autoDelete_)
  24. : ComponentMovementWatcher (comp),
  25. component (comp), returnValue (0),
  26. isActive (true), autoDelete (autoDelete_)
  27. {
  28. jassert (comp != nullptr);
  29. }
  30. void componentMovedOrResized (bool, bool) {}
  31. void componentPeerChanged()
  32. {
  33. if (! component->isShowing())
  34. cancel();
  35. }
  36. void componentVisibilityChanged()
  37. {
  38. if (! component->isShowing())
  39. cancel();
  40. }
  41. void componentBeingDeleted (Component& comp)
  42. {
  43. ComponentMovementWatcher::componentBeingDeleted (comp);
  44. if (component == &comp || comp.isParentOf (component))
  45. {
  46. autoDelete = false;
  47. cancel();
  48. }
  49. }
  50. void cancel()
  51. {
  52. if (isActive)
  53. {
  54. isActive = false;
  55. ModalComponentManager::getInstance()->triggerAsyncUpdate();
  56. }
  57. }
  58. Component* component;
  59. OwnedArray<Callback> callbacks;
  60. int returnValue;
  61. bool isActive, autoDelete;
  62. private:
  63. JUCE_DECLARE_NON_COPYABLE (ModalItem);
  64. };
  65. //==============================================================================
  66. ModalComponentManager::ModalComponentManager()
  67. {
  68. }
  69. ModalComponentManager::~ModalComponentManager()
  70. {
  71. clearSingletonInstance();
  72. }
  73. juce_ImplementSingleton_SingleThreaded (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. ScopedPointer<Callback> callbackDeleter (callback);
  85. for (int i = stack.size(); --i >= 0;)
  86. {
  87. ModalItem* const 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. ModalItem* const 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. ModalItem* const 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 (int i = 0; i < stack.size(); ++i)
  122. if (stack.getUnchecked(i)->isActive)
  123. ++n;
  124. return n;
  125. }
  126. Component* ModalComponentManager::getModalComponent (const int index) const
  127. {
  128. int n = 0;
  129. for (int i = stack.size(); --i >= 0;)
  130. {
  131. const ModalItem* const 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 (Component* const comp) const
  139. {
  140. for (int i = stack.size(); --i >= 0;)
  141. {
  142. const ModalItem* const item = stack.getUnchecked(i);
  143. if (item->isActive && item->component == comp)
  144. return true;
  145. }
  146. return false;
  147. }
  148. bool ModalComponentManager::isFrontModalComponent (Component* const comp) const
  149. {
  150. return comp == getModalComponent (0);
  151. }
  152. void ModalComponentManager::handleAsyncUpdate()
  153. {
  154. for (int i = stack.size(); --i >= 0;)
  155. {
  156. const ModalItem* const item = stack.getUnchecked(i);
  157. if (! item->isActive)
  158. {
  159. ScopedPointer<ModalItem> deleter (stack.removeAndReturn (i));
  160. Component::SafePointer<Component> compToDelete (item->autoDelete ? item->component : nullptr);
  161. for (int j = item->callbacks.size(); --j >= 0;)
  162. item->callbacks.getUnchecked(j)->modalStateFinished (item->returnValue);
  163. compToDelete.deleteAndZero();
  164. }
  165. }
  166. }
  167. void ModalComponentManager::bringModalComponentsToFront (bool topOneShouldGrabFocus)
  168. {
  169. ComponentPeer* lastOne = nullptr;
  170. for (int i = 0; i < getNumModalComponents(); ++i)
  171. {
  172. Component* const c = getModalComponent (i);
  173. if (c == nullptr)
  174. break;
  175. ComponentPeer* peer = c->getPeer();
  176. if (peer != nullptr && peer != lastOne)
  177. {
  178. if (lastOne == nullptr)
  179. {
  180. peer->toFront (topOneShouldGrabFocus);
  181. if (topOneShouldGrabFocus)
  182. peer->grabFocus();
  183. }
  184. else
  185. peer->toBehind (lastOne);
  186. lastOne = peer;
  187. }
  188. }
  189. }
  190. #if JUCE_MODAL_LOOPS_PERMITTED
  191. class ModalComponentManager::ReturnValueRetriever : public ModalComponentManager::Callback
  192. {
  193. public:
  194. ReturnValueRetriever (int& value_, bool& finished_) : value (value_), finished (finished_) {}
  195. void modalStateFinished (int returnValue)
  196. {
  197. finished = true;
  198. value = returnValue;
  199. }
  200. private:
  201. int& value;
  202. bool& finished;
  203. JUCE_DECLARE_NON_COPYABLE (ReturnValueRetriever);
  204. };
  205. int ModalComponentManager::runEventLoopForCurrentComponent()
  206. {
  207. // This can only be run from the message thread!
  208. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  209. Component* currentlyModal = getModalComponent (0);
  210. if (currentlyModal == nullptr)
  211. return 0;
  212. WeakReference<Component> prevFocused (Component::getCurrentlyFocusedComponent());
  213. int returnValue = 0;
  214. bool finished = false;
  215. attachCallback (currentlyModal, new ReturnValueRetriever (returnValue, finished));
  216. JUCE_TRY
  217. {
  218. while (! finished)
  219. {
  220. if (! MessageManager::getInstance()->runDispatchLoopUntil (20))
  221. break;
  222. }
  223. }
  224. JUCE_CATCH_EXCEPTION
  225. if (prevFocused != nullptr)
  226. prevFocused->grabKeyboardFocus();
  227. return returnValue;
  228. }
  229. #endif
  230. END_JUCE_NAMESPACE