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.

299 lines
7.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 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. #include "../../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "juce_Component.h"
  21. #include "juce_ModalComponentManager.h"
  22. #include "windows/juce_ComponentPeer.h"
  23. #include "../../events/juce_MessageManager.h"
  24. #include "../../application/juce_Application.h"
  25. #include "layout/juce_ComponentMovementWatcher.h"
  26. //==============================================================================
  27. class ModalComponentManager::ModalItem : public ComponentMovementWatcher
  28. {
  29. public:
  30. ModalItem (Component* const comp, Callback* const callback)
  31. : ComponentMovementWatcher (comp),
  32. component (comp), returnValue (0), isActive (true)
  33. {
  34. jassert (comp != 0);
  35. if (callback != 0)
  36. callbacks.add (callback);
  37. }
  38. void componentMovedOrResized (bool, bool) {}
  39. void componentPeerChanged()
  40. {
  41. if (! component->isShowing())
  42. cancel();
  43. }
  44. void componentVisibilityChanged()
  45. {
  46. if (! component->isShowing())
  47. cancel();
  48. }
  49. void componentBeingDeleted (Component& comp)
  50. {
  51. ComponentMovementWatcher::componentBeingDeleted (comp);
  52. if (component == &comp || comp.isParentOf (component))
  53. cancel();
  54. }
  55. void cancel()
  56. {
  57. if (isActive)
  58. {
  59. isActive = false;
  60. ModalComponentManager::getInstance()->triggerAsyncUpdate();
  61. }
  62. }
  63. Component* component;
  64. OwnedArray<Callback> callbacks;
  65. int returnValue;
  66. bool isActive;
  67. private:
  68. JUCE_DECLARE_NON_COPYABLE (ModalItem);
  69. };
  70. //==============================================================================
  71. ModalComponentManager::ModalComponentManager()
  72. {
  73. }
  74. ModalComponentManager::~ModalComponentManager()
  75. {
  76. clearSingletonInstance();
  77. }
  78. juce_ImplementSingleton_SingleThreaded (ModalComponentManager);
  79. //==============================================================================
  80. void ModalComponentManager::startModal (Component* component, Callback* callback)
  81. {
  82. if (component != 0)
  83. stack.add (new ModalItem (component, callback));
  84. }
  85. void ModalComponentManager::attachCallback (Component* component, Callback* callback)
  86. {
  87. if (callback != 0)
  88. {
  89. ScopedPointer<Callback> callbackDeleter (callback);
  90. for (int i = stack.size(); --i >= 0;)
  91. {
  92. ModalItem* const 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. ModalItem* const 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. ModalItem* const 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 (int i = 0; i < stack.size(); ++i)
  127. if (stack.getUnchecked(i)->isActive)
  128. ++n;
  129. return n;
  130. }
  131. Component* ModalComponentManager::getModalComponent (const int index) const
  132. {
  133. int n = 0;
  134. for (int i = stack.size(); --i >= 0;)
  135. {
  136. const ModalItem* const item = stack.getUnchecked(i);
  137. if (item->isActive)
  138. if (n++ == index)
  139. return item->component;
  140. }
  141. return 0;
  142. }
  143. bool ModalComponentManager::isModal (Component* const comp) const
  144. {
  145. for (int i = stack.size(); --i >= 0;)
  146. {
  147. const ModalItem* const item = stack.getUnchecked(i);
  148. if (item->isActive && item->component == comp)
  149. return true;
  150. }
  151. return false;
  152. }
  153. bool ModalComponentManager::isFrontModalComponent (Component* const comp) const
  154. {
  155. return comp == getModalComponent (0);
  156. }
  157. void ModalComponentManager::handleAsyncUpdate()
  158. {
  159. for (int i = stack.size(); --i >= 0;)
  160. {
  161. const ModalItem* const item = stack.getUnchecked(i);
  162. if (! item->isActive)
  163. {
  164. for (int j = item->callbacks.size(); --j >= 0;)
  165. {
  166. item->callbacks.getUnchecked(j)->modalStateFinished (item->returnValue);
  167. if (! stack.contains (item))
  168. break;
  169. }
  170. stack.removeObject (item);
  171. }
  172. }
  173. }
  174. void ModalComponentManager::bringModalComponentsToFront()
  175. {
  176. ComponentPeer* lastOne = 0;
  177. for (int i = 0; i < getNumModalComponents(); ++i)
  178. {
  179. Component* const c = getModalComponent (i);
  180. if (c == 0)
  181. break;
  182. ComponentPeer* peer = c->getPeer();
  183. if (peer != 0 && peer != lastOne)
  184. {
  185. if (lastOne == 0)
  186. {
  187. peer->toFront (true);
  188. peer->grabFocus();
  189. }
  190. else
  191. peer->toBehind (lastOne);
  192. lastOne = peer;
  193. }
  194. }
  195. }
  196. class ModalComponentManager::ReturnValueRetriever : public ModalComponentManager::Callback
  197. {
  198. public:
  199. ReturnValueRetriever (int& value_, bool& finished_) : value (value_), finished (finished_) {}
  200. ~ReturnValueRetriever() {}
  201. void modalStateFinished (int returnValue)
  202. {
  203. finished = true;
  204. value = returnValue;
  205. }
  206. private:
  207. int& value;
  208. bool& finished;
  209. JUCE_DECLARE_NON_COPYABLE (ReturnValueRetriever);
  210. };
  211. int ModalComponentManager::runEventLoopForCurrentComponent()
  212. {
  213. // This can only be run from the message thread!
  214. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  215. Component* currentlyModal = getModalComponent (0);
  216. if (currentlyModal == 0)
  217. return 0;
  218. WeakReference<Component> prevFocused (Component::getCurrentlyFocusedComponent());
  219. int returnValue = 0;
  220. bool finished = false;
  221. attachCallback (currentlyModal, new ReturnValueRetriever (returnValue, finished));
  222. JUCE_TRY
  223. {
  224. while (! finished)
  225. {
  226. if (! MessageManager::getInstance()->runDispatchLoopUntil (20))
  227. break;
  228. }
  229. }
  230. JUCE_CATCH_EXCEPTION
  231. if (prevFocused != 0)
  232. prevFocused->grabKeyboardFocus();
  233. return returnValue;
  234. }
  235. END_JUCE_NAMESPACE