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.

552 lines
17KB

  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_ComponentPeer.h"
  21. #include "../../../application/juce_Application.h"
  22. #include "../juce_Desktop.h"
  23. #include "../../../events/juce_MessageManager.h"
  24. #include "../../../core/juce_Time.h"
  25. #include "../../../core/juce_Random.h"
  26. #include "../layout/juce_ComponentBoundsConstrainer.h"
  27. #include "../mouse/juce_FileDragAndDropTarget.h"
  28. #include "../mouse/juce_MouseInputSource.h"
  29. //#define JUCE_ENABLE_REPAINT_DEBUGGING 1
  30. //==============================================================================
  31. static Array <ComponentPeer*> heavyweightPeers;
  32. //==============================================================================
  33. ComponentPeer::ComponentPeer (Component* const component_, const int styleFlags_)
  34. : component (component_),
  35. styleFlags (styleFlags_),
  36. lastPaintTime (0),
  37. constrainer (0),
  38. lastDragAndDropCompUnderMouse (0),
  39. fakeMouseMessageSent (false),
  40. isWindowMinimised (false)
  41. {
  42. heavyweightPeers.add (this);
  43. }
  44. ComponentPeer::~ComponentPeer()
  45. {
  46. heavyweightPeers.removeValue (this);
  47. Desktop::getInstance().triggerFocusCallback();
  48. }
  49. //==============================================================================
  50. int ComponentPeer::getNumPeers() throw()
  51. {
  52. return heavyweightPeers.size();
  53. }
  54. ComponentPeer* ComponentPeer::getPeer (const int index) throw()
  55. {
  56. return heavyweightPeers [index];
  57. }
  58. ComponentPeer* ComponentPeer::getPeerFor (const Component* const component) throw()
  59. {
  60. for (int i = heavyweightPeers.size(); --i >= 0;)
  61. {
  62. ComponentPeer* const peer = heavyweightPeers.getUnchecked(i);
  63. if (peer->getComponent() == component)
  64. return peer;
  65. }
  66. return 0;
  67. }
  68. bool ComponentPeer::isValidPeer (const ComponentPeer* const peer) throw()
  69. {
  70. return heavyweightPeers.contains (const_cast <ComponentPeer*> (peer));
  71. }
  72. void ComponentPeer::updateCurrentModifiers() throw()
  73. {
  74. ModifierKeys::updateCurrentModifiers();
  75. }
  76. //==============================================================================
  77. void ComponentPeer::handleMouseEvent (const int touchIndex, const Point<int>& positionWithinPeer, const ModifierKeys& newMods, const int64 time)
  78. {
  79. MouseInputSource* const mouse = Desktop::getInstance().getMouseSource (touchIndex);
  80. jassert (mouse != 0); // not enough sources!
  81. mouse->handleEvent (this, positionWithinPeer, time, newMods);
  82. }
  83. void ComponentPeer::handleMouseWheel (const int touchIndex, const Point<int>& positionWithinPeer, const int64 time, const float x, const float y)
  84. {
  85. MouseInputSource* const mouse = Desktop::getInstance().getMouseSource (touchIndex);
  86. jassert (mouse != 0); // not enough sources!
  87. mouse->handleWheel (this, positionWithinPeer, time, x, y);
  88. }
  89. //==============================================================================
  90. void ComponentPeer::handlePaint (LowLevelGraphicsContext& contextToPaintTo)
  91. {
  92. Graphics g (&contextToPaintTo);
  93. #if JUCE_ENABLE_REPAINT_DEBUGGING
  94. g.saveState();
  95. #endif
  96. JUCE_TRY
  97. {
  98. component->paintEntireComponent (g, true);
  99. }
  100. JUCE_CATCH_EXCEPTION
  101. #if JUCE_ENABLE_REPAINT_DEBUGGING
  102. // enabling this code will fill all areas that get repainted with a colour overlay, to show
  103. // clearly when things are being repainted.
  104. {
  105. g.restoreState();
  106. g.fillAll (Colour ((uint8) Random::getSystemRandom().nextInt (255),
  107. (uint8) Random::getSystemRandom().nextInt (255),
  108. (uint8) Random::getSystemRandom().nextInt (255),
  109. (uint8) 0x50));
  110. }
  111. #endif
  112. /** If this fails, it's probably be because your CPU floating-point precision mode has
  113. been set to low.. This setting is sometimes changed by things like Direct3D, and can
  114. mess up a lot of the calculations that the library needs to do.
  115. */
  116. jassert (roundToInt (10.1f) == 10);
  117. }
  118. bool ComponentPeer::handleKeyPress (const int keyCode,
  119. const juce_wchar textCharacter)
  120. {
  121. updateCurrentModifiers();
  122. Component* target = Component::getCurrentlyFocusedComponent() != 0
  123. ? Component::getCurrentlyFocusedComponent()
  124. : component;
  125. if (target->isCurrentlyBlockedByAnotherModalComponent())
  126. {
  127. Component* const currentModalComp = Component::getCurrentlyModalComponent();
  128. if (currentModalComp != 0)
  129. target = currentModalComp;
  130. }
  131. const KeyPress keyInfo (keyCode,
  132. ModifierKeys::getCurrentModifiers().getRawFlags()
  133. & ModifierKeys::allKeyboardModifiers,
  134. textCharacter);
  135. bool keyWasUsed = false;
  136. while (target != 0)
  137. {
  138. const Component::SafePointer<Component> deletionChecker (target);
  139. if (target->keyListeners_ != 0)
  140. {
  141. for (int i = target->keyListeners_->size(); --i >= 0;)
  142. {
  143. keyWasUsed = target->keyListeners_->getUnchecked(i)->keyPressed (keyInfo, target);
  144. if (keyWasUsed || deletionChecker == 0)
  145. return keyWasUsed;
  146. i = jmin (i, target->keyListeners_->size());
  147. }
  148. }
  149. keyWasUsed = target->keyPressed (keyInfo);
  150. if (keyWasUsed || deletionChecker == 0)
  151. break;
  152. if (keyInfo.isKeyCode (KeyPress::tabKey) && Component::getCurrentlyFocusedComponent() != 0)
  153. {
  154. Component* const currentlyFocused = Component::getCurrentlyFocusedComponent();
  155. currentlyFocused->moveKeyboardFocusToSibling (! keyInfo.getModifiers().isShiftDown());
  156. keyWasUsed = (currentlyFocused != Component::getCurrentlyFocusedComponent());
  157. break;
  158. }
  159. target = target->parentComponent_;
  160. }
  161. return keyWasUsed;
  162. }
  163. bool ComponentPeer::handleKeyUpOrDown (const bool isKeyDown)
  164. {
  165. updateCurrentModifiers();
  166. Component* target = Component::getCurrentlyFocusedComponent() != 0
  167. ? Component::getCurrentlyFocusedComponent()
  168. : component;
  169. if (target->isCurrentlyBlockedByAnotherModalComponent())
  170. {
  171. Component* const currentModalComp = Component::getCurrentlyModalComponent();
  172. if (currentModalComp != 0)
  173. target = currentModalComp;
  174. }
  175. bool keyWasUsed = false;
  176. while (target != 0)
  177. {
  178. const Component::SafePointer<Component> deletionChecker (target);
  179. keyWasUsed = target->keyStateChanged (isKeyDown);
  180. if (keyWasUsed || deletionChecker == 0)
  181. break;
  182. if (target->keyListeners_ != 0)
  183. {
  184. for (int i = target->keyListeners_->size(); --i >= 0;)
  185. {
  186. keyWasUsed = target->keyListeners_->getUnchecked(i)->keyStateChanged (isKeyDown, target);
  187. if (keyWasUsed || deletionChecker == 0)
  188. return keyWasUsed;
  189. i = jmin (i, target->keyListeners_->size());
  190. }
  191. }
  192. target = target->parentComponent_;
  193. }
  194. return keyWasUsed;
  195. }
  196. void ComponentPeer::handleModifierKeysChange()
  197. {
  198. updateCurrentModifiers();
  199. Component* target = Desktop::getInstance().getMainMouseSource().getComponentUnderMouse();
  200. if (target == 0)
  201. target = Component::getCurrentlyFocusedComponent();
  202. if (target == 0)
  203. target = component;
  204. if (target != 0)
  205. target->internalModifierKeysChanged();
  206. }
  207. TextInputTarget* ComponentPeer::findCurrentTextInputTarget()
  208. {
  209. Component* const c = Component::getCurrentlyFocusedComponent();
  210. if (component->isParentOf (c))
  211. {
  212. TextInputTarget* const ti = dynamic_cast <TextInputTarget*> (c);
  213. if (ti != 0 && ti->isTextInputActive())
  214. return ti;
  215. }
  216. return 0;
  217. }
  218. //==============================================================================
  219. void ComponentPeer::handleBroughtToFront()
  220. {
  221. updateCurrentModifiers();
  222. if (component != 0)
  223. component->internalBroughtToFront();
  224. }
  225. void ComponentPeer::setConstrainer (ComponentBoundsConstrainer* const newConstrainer) throw()
  226. {
  227. constrainer = newConstrainer;
  228. }
  229. void ComponentPeer::handleMovedOrResized()
  230. {
  231. updateCurrentModifiers();
  232. const bool nowMinimised = isMinimised();
  233. if (component->flags.hasHeavyweightPeerFlag && ! nowMinimised)
  234. {
  235. const Component::SafePointer<Component> deletionChecker (component);
  236. const Rectangle<int> newBounds (getBounds());
  237. const bool wasMoved = (component->getPosition() != newBounds.getPosition());
  238. const bool wasResized = (component->getWidth() != newBounds.getWidth() || component->getHeight() != newBounds.getHeight());
  239. if (wasMoved || wasResized)
  240. {
  241. component->bounds_ = newBounds;
  242. if (wasResized)
  243. component->repaint();
  244. component->sendMovedResizedMessages (wasMoved, wasResized);
  245. if (deletionChecker == 0)
  246. return;
  247. }
  248. }
  249. if (isWindowMinimised != nowMinimised)
  250. {
  251. isWindowMinimised = nowMinimised;
  252. component->minimisationStateChanged (nowMinimised);
  253. component->sendVisibilityChangeMessage();
  254. }
  255. if (! isFullScreen())
  256. lastNonFullscreenBounds = component->getBounds();
  257. }
  258. void ComponentPeer::handleFocusGain()
  259. {
  260. updateCurrentModifiers();
  261. if (component->isParentOf (lastFocusedComponent))
  262. {
  263. Component::currentlyFocusedComponent = lastFocusedComponent;
  264. Desktop::getInstance().triggerFocusCallback();
  265. lastFocusedComponent->internalFocusGain (Component::focusChangedDirectly);
  266. }
  267. else
  268. {
  269. if (! component->isCurrentlyBlockedByAnotherModalComponent())
  270. component->grabKeyboardFocus();
  271. else
  272. ModalComponentManager::getInstance()->bringModalComponentsToFront();
  273. }
  274. }
  275. void ComponentPeer::handleFocusLoss()
  276. {
  277. updateCurrentModifiers();
  278. if (component->hasKeyboardFocus (true))
  279. {
  280. lastFocusedComponent = Component::currentlyFocusedComponent;
  281. if (lastFocusedComponent != 0)
  282. {
  283. Component::currentlyFocusedComponent = 0;
  284. Desktop::getInstance().triggerFocusCallback();
  285. lastFocusedComponent->internalFocusLoss (Component::focusChangedByMouseClick);
  286. }
  287. }
  288. }
  289. Component* ComponentPeer::getLastFocusedSubcomponent() const throw()
  290. {
  291. return (component->isParentOf (lastFocusedComponent) && lastFocusedComponent->isShowing())
  292. ? static_cast <Component*> (lastFocusedComponent)
  293. : component;
  294. }
  295. void ComponentPeer::handleScreenSizeChange()
  296. {
  297. updateCurrentModifiers();
  298. component->parentSizeChanged();
  299. handleMovedOrResized();
  300. }
  301. void ComponentPeer::setNonFullScreenBounds (const Rectangle<int>& newBounds) throw()
  302. {
  303. lastNonFullscreenBounds = newBounds;
  304. }
  305. const Rectangle<int>& ComponentPeer::getNonFullScreenBounds() const throw()
  306. {
  307. return lastNonFullscreenBounds;
  308. }
  309. const Rectangle<int> ComponentPeer::localToGlobal (const Rectangle<int>& relativePosition)
  310. {
  311. return relativePosition.withPosition (localToGlobal (relativePosition.getPosition()));
  312. }
  313. const Rectangle<int> ComponentPeer::globalToLocal (const Rectangle<int>& screenPosition)
  314. {
  315. return screenPosition.withPosition (globalToLocal (screenPosition.getPosition()));
  316. }
  317. //==============================================================================
  318. namespace ComponentPeerHelpers
  319. {
  320. FileDragAndDropTarget* findDragAndDropTarget (Component* c,
  321. const StringArray& files,
  322. FileDragAndDropTarget* const lastOne)
  323. {
  324. while (c != 0)
  325. {
  326. FileDragAndDropTarget* const t = dynamic_cast <FileDragAndDropTarget*> (c);
  327. if (t != 0 && (t == lastOne || t->isInterestedInFileDrag (files)))
  328. return t;
  329. c = c->getParentComponent();
  330. }
  331. return 0;
  332. }
  333. }
  334. void ComponentPeer::handleFileDragMove (const StringArray& files, const Point<int>& position)
  335. {
  336. updateCurrentModifiers();
  337. FileDragAndDropTarget* lastTarget
  338. = dynamic_cast<FileDragAndDropTarget*> (static_cast<Component*> (dragAndDropTargetComponent));
  339. FileDragAndDropTarget* newTarget = 0;
  340. Component* const compUnderMouse = component->getComponentAt (position);
  341. if (compUnderMouse != lastDragAndDropCompUnderMouse)
  342. {
  343. lastDragAndDropCompUnderMouse = compUnderMouse;
  344. newTarget = ComponentPeerHelpers::findDragAndDropTarget (compUnderMouse, files, lastTarget);
  345. if (newTarget != lastTarget)
  346. {
  347. if (lastTarget != 0)
  348. lastTarget->fileDragExit (files);
  349. dragAndDropTargetComponent = 0;
  350. if (newTarget != 0)
  351. {
  352. dragAndDropTargetComponent = dynamic_cast <Component*> (newTarget);
  353. const Point<int> pos (dragAndDropTargetComponent->getLocalPoint (component, position));
  354. newTarget->fileDragEnter (files, pos.getX(), pos.getY());
  355. }
  356. }
  357. }
  358. else
  359. {
  360. newTarget = lastTarget;
  361. }
  362. if (newTarget != 0)
  363. {
  364. Component* const targetComp = dynamic_cast <Component*> (newTarget);
  365. const Point<int> pos (targetComp->getLocalPoint (component, position));
  366. newTarget->fileDragMove (files, pos.getX(), pos.getY());
  367. }
  368. }
  369. void ComponentPeer::handleFileDragExit (const StringArray& files)
  370. {
  371. handleFileDragMove (files, Point<int> (-1, -1));
  372. jassert (dragAndDropTargetComponent == 0);
  373. lastDragAndDropCompUnderMouse = 0;
  374. }
  375. void ComponentPeer::handleFileDragDrop (const StringArray& files, const Point<int>& position)
  376. {
  377. handleFileDragMove (files, position);
  378. if (dragAndDropTargetComponent != 0)
  379. {
  380. FileDragAndDropTarget* const target
  381. = dynamic_cast<FileDragAndDropTarget*> (static_cast<Component*> (dragAndDropTargetComponent));
  382. dragAndDropTargetComponent = 0;
  383. lastDragAndDropCompUnderMouse = 0;
  384. if (target != 0)
  385. {
  386. Component* const targetComp = dynamic_cast <Component*> (target);
  387. if (targetComp->isCurrentlyBlockedByAnotherModalComponent())
  388. {
  389. targetComp->internalModalInputAttempt();
  390. if (targetComp->isCurrentlyBlockedByAnotherModalComponent())
  391. return;
  392. }
  393. const Point<int> pos (targetComp->getLocalPoint (component, position));
  394. target->filesDropped (files, pos.getX(), pos.getY());
  395. }
  396. }
  397. }
  398. //==============================================================================
  399. void ComponentPeer::handleUserClosingWindow()
  400. {
  401. updateCurrentModifiers();
  402. component->userTriedToCloseWindow();
  403. }
  404. //==============================================================================
  405. void ComponentPeer::clearMaskedRegion()
  406. {
  407. maskedRegion.clear();
  408. }
  409. void ComponentPeer::addMaskedRegion (int x, int y, int w, int h)
  410. {
  411. maskedRegion.add (x, y, w, h);
  412. }
  413. //==============================================================================
  414. const StringArray ComponentPeer::getAvailableRenderingEngines()
  415. {
  416. StringArray s;
  417. s.add ("Software Renderer");
  418. return s;
  419. }
  420. int ComponentPeer::getCurrentRenderingEngine() throw()
  421. {
  422. return 0;
  423. }
  424. void ComponentPeer::setCurrentRenderingEngine (int /*index*/)
  425. {
  426. }
  427. END_JUCE_NAMESPACE