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.

547 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. jassert (component->isValidComponent());
  232. updateCurrentModifiers();
  233. const bool nowMinimised = isMinimised();
  234. if (component->flags.hasHeavyweightPeerFlag && ! nowMinimised)
  235. {
  236. const Component::SafePointer<Component> deletionChecker (component);
  237. const Rectangle<int> newBounds (getBounds());
  238. const bool wasMoved = (component->getPosition() != newBounds.getPosition());
  239. const bool wasResized = (component->getWidth() != newBounds.getWidth() || component->getHeight() != newBounds.getHeight());
  240. if (wasMoved || wasResized)
  241. {
  242. component->bounds_ = newBounds;
  243. if (wasResized)
  244. component->repaint();
  245. component->sendMovedResizedMessages (wasMoved, wasResized);
  246. if (deletionChecker == 0)
  247. return;
  248. }
  249. }
  250. if (isWindowMinimised != nowMinimised)
  251. {
  252. isWindowMinimised = nowMinimised;
  253. component->minimisationStateChanged (nowMinimised);
  254. component->sendVisibilityChangeMessage();
  255. }
  256. if (! isFullScreen())
  257. lastNonFullscreenBounds = component->getBounds();
  258. }
  259. void ComponentPeer::handleFocusGain()
  260. {
  261. updateCurrentModifiers();
  262. if (component->isParentOf (lastFocusedComponent))
  263. {
  264. Component::currentlyFocusedComponent = lastFocusedComponent;
  265. Desktop::getInstance().triggerFocusCallback();
  266. lastFocusedComponent->internalFocusGain (Component::focusChangedDirectly);
  267. }
  268. else
  269. {
  270. if (! component->isCurrentlyBlockedByAnotherModalComponent())
  271. component->grabKeyboardFocus();
  272. else
  273. Component::bringModalComponentToFront();
  274. }
  275. }
  276. void ComponentPeer::handleFocusLoss()
  277. {
  278. updateCurrentModifiers();
  279. if (component->hasKeyboardFocus (true))
  280. {
  281. lastFocusedComponent = Component::currentlyFocusedComponent;
  282. if (lastFocusedComponent != 0)
  283. {
  284. Component::currentlyFocusedComponent = 0;
  285. Desktop::getInstance().triggerFocusCallback();
  286. lastFocusedComponent->internalFocusLoss (Component::focusChangedByMouseClick);
  287. }
  288. }
  289. }
  290. Component* ComponentPeer::getLastFocusedSubcomponent() const throw()
  291. {
  292. return (component->isParentOf (lastFocusedComponent) && lastFocusedComponent->isShowing())
  293. ? static_cast <Component*> (lastFocusedComponent)
  294. : component;
  295. }
  296. void ComponentPeer::handleScreenSizeChange()
  297. {
  298. updateCurrentModifiers();
  299. component->parentSizeChanged();
  300. handleMovedOrResized();
  301. }
  302. void ComponentPeer::setNonFullScreenBounds (const Rectangle<int>& newBounds) throw()
  303. {
  304. lastNonFullscreenBounds = newBounds;
  305. }
  306. const Rectangle<int>& ComponentPeer::getNonFullScreenBounds() const throw()
  307. {
  308. return lastNonFullscreenBounds;
  309. }
  310. //==============================================================================
  311. static FileDragAndDropTarget* findDragAndDropTarget (Component* c,
  312. const StringArray& files,
  313. FileDragAndDropTarget* const lastOne)
  314. {
  315. while (c != 0)
  316. {
  317. FileDragAndDropTarget* const t = dynamic_cast <FileDragAndDropTarget*> (c);
  318. if (t != 0 && (t == lastOne || t->isInterestedInFileDrag (files)))
  319. return t;
  320. c = c->getParentComponent();
  321. }
  322. return 0;
  323. }
  324. void ComponentPeer::handleFileDragMove (const StringArray& files, const Point<int>& position)
  325. {
  326. updateCurrentModifiers();
  327. FileDragAndDropTarget* lastTarget
  328. = dynamic_cast<FileDragAndDropTarget*> (static_cast<Component*> (dragAndDropTargetComponent));
  329. FileDragAndDropTarget* newTarget = 0;
  330. Component* const compUnderMouse = component->getComponentAt (position);
  331. if (compUnderMouse != lastDragAndDropCompUnderMouse)
  332. {
  333. lastDragAndDropCompUnderMouse = compUnderMouse;
  334. newTarget = findDragAndDropTarget (compUnderMouse, files, lastTarget);
  335. if (newTarget != lastTarget)
  336. {
  337. if (lastTarget != 0)
  338. lastTarget->fileDragExit (files);
  339. dragAndDropTargetComponent = 0;
  340. if (newTarget != 0)
  341. {
  342. dragAndDropTargetComponent = dynamic_cast <Component*> (newTarget);
  343. const Point<int> pos (component->relativePositionToOtherComponent (dragAndDropTargetComponent, position));
  344. newTarget->fileDragEnter (files, pos.getX(), pos.getY());
  345. }
  346. }
  347. }
  348. else
  349. {
  350. newTarget = lastTarget;
  351. }
  352. if (newTarget != 0)
  353. {
  354. Component* const targetComp = dynamic_cast <Component*> (newTarget);
  355. const Point<int> pos (component->relativePositionToOtherComponent (targetComp, position));
  356. newTarget->fileDragMove (files, pos.getX(), pos.getY());
  357. }
  358. }
  359. void ComponentPeer::handleFileDragExit (const StringArray& files)
  360. {
  361. handleFileDragMove (files, Point<int> (-1, -1));
  362. jassert (dragAndDropTargetComponent == 0);
  363. lastDragAndDropCompUnderMouse = 0;
  364. }
  365. void ComponentPeer::handleFileDragDrop (const StringArray& files, const Point<int>& position)
  366. {
  367. handleFileDragMove (files, position);
  368. if (dragAndDropTargetComponent != 0)
  369. {
  370. FileDragAndDropTarget* const target
  371. = dynamic_cast<FileDragAndDropTarget*> (static_cast<Component*> (dragAndDropTargetComponent));
  372. dragAndDropTargetComponent = 0;
  373. lastDragAndDropCompUnderMouse = 0;
  374. if (target != 0)
  375. {
  376. Component* const targetComp = dynamic_cast <Component*> (target);
  377. if (targetComp->isCurrentlyBlockedByAnotherModalComponent())
  378. {
  379. targetComp->internalModalInputAttempt();
  380. if (targetComp->isCurrentlyBlockedByAnotherModalComponent())
  381. return;
  382. }
  383. const Point<int> pos (component->relativePositionToOtherComponent (targetComp, position));
  384. target->filesDropped (files, pos.getX(), pos.getY());
  385. }
  386. }
  387. }
  388. //==============================================================================
  389. void ComponentPeer::handleUserClosingWindow()
  390. {
  391. updateCurrentModifiers();
  392. component->userTriedToCloseWindow();
  393. }
  394. //==============================================================================
  395. void ComponentPeer::bringModalComponentToFront()
  396. {
  397. Component::bringModalComponentToFront();
  398. }
  399. //==============================================================================
  400. void ComponentPeer::clearMaskedRegion()
  401. {
  402. maskedRegion.clear();
  403. }
  404. void ComponentPeer::addMaskedRegion (int x, int y, int w, int h)
  405. {
  406. maskedRegion.add (x, y, w, h);
  407. }
  408. //==============================================================================
  409. const StringArray ComponentPeer::getAvailableRenderingEngines()
  410. {
  411. StringArray s;
  412. s.add ("Software Renderer");
  413. return s;
  414. }
  415. int ComponentPeer::getCurrentRenderingEngine() throw()
  416. {
  417. return 0;
  418. }
  419. void ComponentPeer::setCurrentRenderingEngine (int /*index*/)
  420. {
  421. }
  422. END_JUCE_NAMESPACE