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.

3689 lines
108KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 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_ComponentDeletionWatcher.h"
  22. #include "juce_Desktop.h"
  23. #include "keyboard/juce_KeyListener.h"
  24. #include "lookandfeel/juce_LookAndFeel.h"
  25. #include "../../application/juce_Application.h"
  26. #include "../graphics/geometry/juce_RectangleList.h"
  27. #include "../graphics/imaging/juce_Image.h"
  28. #include "../graphics/contexts/juce_LowLevelGraphicsContext.h"
  29. #include "../../events/juce_MessageManager.h"
  30. #include "../../events/juce_Timer.h"
  31. #include "../../core/juce_Time.h"
  32. #include "../../core/juce_PlatformUtilities.h"
  33. //==============================================================================
  34. Component* Component::componentUnderMouse = 0;
  35. Component* Component::currentlyFocusedComponent = 0;
  36. static Array <Component*> modalComponentStack (4), modalComponentReturnValueKeys (4);
  37. static Array <int> modalReturnValues (4);
  38. static const int customCommandMessage = 0x7fff0001;
  39. static const int exitModalStateMessage = 0x7fff0002;
  40. //==============================================================================
  41. // these are also used by ComponentPeer
  42. int64 juce_recentMouseDownTimes [4] = { 0, 0, 0, 0 };
  43. int juce_recentMouseDownX [4] = { 0, 0, 0, 0 };
  44. int juce_recentMouseDownY [4] = { 0, 0, 0, 0 };
  45. Component* juce_recentMouseDownComponent [4] = { 0, 0, 0, 0 };
  46. int juce_LastMousePosX = 0;
  47. int juce_LastMousePosY = 0;
  48. int juce_MouseClickCounter = 0;
  49. bool juce_MouseHasMovedSignificantlySincePressed = false;
  50. static int countMouseClicks() throw()
  51. {
  52. int numClicks = 0;
  53. if (juce_recentMouseDownTimes[0] != 0)
  54. {
  55. if (! juce_MouseHasMovedSignificantlySincePressed)
  56. ++numClicks;
  57. for (int i = 1; i < numElementsInArray (juce_recentMouseDownTimes); ++i)
  58. {
  59. if (juce_recentMouseDownTimes[0] - juce_recentMouseDownTimes [i]
  60. < (int) (MouseEvent::getDoubleClickTimeout() * (1.0 + 0.25 * (i - 1)))
  61. && abs (juce_recentMouseDownX[0] - juce_recentMouseDownX[i]) < 8
  62. && abs (juce_recentMouseDownY[0] - juce_recentMouseDownY[i]) < 8
  63. && juce_recentMouseDownComponent[0] == juce_recentMouseDownComponent [i])
  64. {
  65. ++numClicks;
  66. }
  67. else
  68. {
  69. break;
  70. }
  71. }
  72. }
  73. return numClicks;
  74. }
  75. static int unboundedMouseOffsetX = 0;
  76. static int unboundedMouseOffsetY = 0;
  77. static bool isUnboundedMouseModeOn = false;
  78. static bool isCursorVisibleUntilOffscreen;
  79. //==============================================================================
  80. #define checkMessageManagerIsLocked jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
  81. static uint32 nextComponentUID = 0;
  82. //==============================================================================
  83. Component::Component() throw()
  84. : parentComponent_ (0),
  85. componentUID (++nextComponentUID),
  86. numDeepMouseListeners (0),
  87. childComponentList_ (16),
  88. lookAndFeel_ (0),
  89. effect_ (0),
  90. bufferedImage_ (0),
  91. mouseListeners_ (0),
  92. keyListeners_ (0),
  93. componentListeners_ (0),
  94. propertySet_ (0),
  95. componentFlags_ (0)
  96. {
  97. }
  98. Component::Component (const String& name) throw()
  99. : componentName_ (name),
  100. parentComponent_ (0),
  101. componentUID (++nextComponentUID),
  102. numDeepMouseListeners (0),
  103. childComponentList_ (16),
  104. lookAndFeel_ (0),
  105. effect_ (0),
  106. bufferedImage_ (0),
  107. mouseListeners_ (0),
  108. keyListeners_ (0),
  109. componentListeners_ (0),
  110. propertySet_ (0),
  111. componentFlags_ (0)
  112. {
  113. }
  114. Component::~Component()
  115. {
  116. if (parentComponent_ != 0)
  117. {
  118. parentComponent_->removeChildComponent (this);
  119. }
  120. else if ((currentlyFocusedComponent == this)
  121. || isParentOf (currentlyFocusedComponent))
  122. {
  123. giveAwayFocus();
  124. }
  125. if (componentUnderMouse == this)
  126. componentUnderMouse = 0;
  127. if (flags.hasHeavyweightPeerFlag)
  128. removeFromDesktop();
  129. modalComponentStack.removeValue (this);
  130. for (int i = childComponentList_.size(); --i >= 0;)
  131. childComponentList_.getUnchecked(i)->parentComponent_ = 0;
  132. delete bufferedImage_;
  133. delete mouseListeners_;
  134. delete keyListeners_;
  135. delete componentListeners_;
  136. delete propertySet_;
  137. }
  138. //==============================================================================
  139. void Component::setName (const String& name)
  140. {
  141. // if component methods are being called from threads other than the message
  142. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  143. checkMessageManagerIsLocked
  144. if (componentName_ != name)
  145. {
  146. componentName_ = name;
  147. if (flags.hasHeavyweightPeerFlag)
  148. {
  149. ComponentPeer* const peer = getPeer();
  150. jassert (peer != 0);
  151. if (peer != 0)
  152. peer->setTitle (name);
  153. }
  154. if (componentListeners_ != 0)
  155. {
  156. const ComponentDeletionWatcher deletionChecker (this);
  157. for (int i = componentListeners_->size(); --i >= 0;)
  158. {
  159. ((ComponentListener*) componentListeners_->getUnchecked (i))
  160. ->componentNameChanged (*this);
  161. if (deletionChecker.hasBeenDeleted())
  162. return;
  163. i = jmin (i, componentListeners_->size());
  164. }
  165. }
  166. }
  167. }
  168. void Component::setVisible (bool shouldBeVisible)
  169. {
  170. if (flags.visibleFlag != shouldBeVisible)
  171. {
  172. // if component methods are being called from threads other than the message
  173. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  174. checkMessageManagerIsLocked
  175. const ComponentDeletionWatcher deletionChecker (this);
  176. flags.visibleFlag = shouldBeVisible;
  177. internalRepaint (0, 0, getWidth(), getHeight());
  178. sendFakeMouseMove();
  179. if (! shouldBeVisible)
  180. {
  181. if (currentlyFocusedComponent == this
  182. || isParentOf (currentlyFocusedComponent))
  183. {
  184. if (parentComponent_ != 0)
  185. parentComponent_->grabKeyboardFocus();
  186. else
  187. giveAwayFocus();
  188. }
  189. }
  190. sendVisibilityChangeMessage();
  191. if ((! deletionChecker.hasBeenDeleted()) && flags.hasHeavyweightPeerFlag)
  192. {
  193. ComponentPeer* const peer = getPeer();
  194. jassert (peer != 0);
  195. if (peer != 0)
  196. {
  197. peer->setVisible (shouldBeVisible);
  198. internalHierarchyChanged();
  199. }
  200. }
  201. }
  202. }
  203. void Component::visibilityChanged()
  204. {
  205. }
  206. void Component::sendVisibilityChangeMessage()
  207. {
  208. const ComponentDeletionWatcher deletionChecker (this);
  209. visibilityChanged();
  210. if ((! deletionChecker.hasBeenDeleted()) && componentListeners_ != 0)
  211. {
  212. for (int i = componentListeners_->size(); --i >= 0;)
  213. {
  214. ((ComponentListener*) componentListeners_->getUnchecked (i))
  215. ->componentVisibilityChanged (*this);
  216. if (deletionChecker.hasBeenDeleted())
  217. return;
  218. i = jmin (i, componentListeners_->size());
  219. }
  220. }
  221. }
  222. bool Component::isShowing() const throw()
  223. {
  224. if (flags.visibleFlag)
  225. {
  226. if (parentComponent_ != 0)
  227. {
  228. return parentComponent_->isShowing();
  229. }
  230. else
  231. {
  232. const ComponentPeer* const peer = getPeer();
  233. return peer != 0 && ! peer->isMinimised();
  234. }
  235. }
  236. return false;
  237. }
  238. //==============================================================================
  239. class FadeOutProxyComponent : public Component,
  240. public Timer
  241. {
  242. public:
  243. FadeOutProxyComponent (Component* comp,
  244. const int fadeLengthMs,
  245. const int deltaXToMove,
  246. const int deltaYToMove,
  247. const float scaleFactorAtEnd)
  248. : lastTime (0),
  249. alpha (1.0f),
  250. scale (1.0f)
  251. {
  252. image = comp->createComponentSnapshot (Rectangle (0, 0, comp->getWidth(), comp->getHeight()));
  253. setBounds (comp->getBounds());
  254. comp->getParentComponent()->addAndMakeVisible (this);
  255. toBehind (comp);
  256. alphaChangePerMs = -1.0f / (float)fadeLengthMs;
  257. centreX = comp->getX() + comp->getWidth() * 0.5f;
  258. xChangePerMs = deltaXToMove / (float)fadeLengthMs;
  259. centreY = comp->getY() + comp->getHeight() * 0.5f;
  260. yChangePerMs = deltaYToMove / (float)fadeLengthMs;
  261. scaleChangePerMs = (scaleFactorAtEnd - 1.0f) / (float)fadeLengthMs;
  262. setInterceptsMouseClicks (false, false);
  263. // 30 fps is enough for a fade, but we need a higher rate if it's moving as well..
  264. startTimer (1000 / ((deltaXToMove == 0 && deltaYToMove == 0) ? 30 : 50));
  265. }
  266. ~FadeOutProxyComponent()
  267. {
  268. delete image;
  269. }
  270. void paint (Graphics& g)
  271. {
  272. g.setOpacity (alpha);
  273. g.drawImage (image,
  274. 0, 0, getWidth(), getHeight(),
  275. 0, 0, image->getWidth(), image->getHeight());
  276. }
  277. void timerCallback()
  278. {
  279. const uint32 now = Time::getMillisecondCounter();
  280. if (lastTime == 0)
  281. lastTime = now;
  282. const int msPassed = (now > lastTime) ? now - lastTime : 0;
  283. lastTime = now;
  284. alpha += alphaChangePerMs * msPassed;
  285. if (alpha > 0)
  286. {
  287. if (xChangePerMs != 0.0f || yChangePerMs != 0.0f || scaleChangePerMs != 0.0f)
  288. {
  289. centreX += xChangePerMs * msPassed;
  290. centreY += yChangePerMs * msPassed;
  291. scale += scaleChangePerMs * msPassed;
  292. const int w = roundFloatToInt (image->getWidth() * scale);
  293. const int h = roundFloatToInt (image->getHeight() * scale);
  294. setBounds (roundFloatToInt (centreX) - w / 2,
  295. roundFloatToInt (centreY) - h / 2,
  296. w, h);
  297. }
  298. repaint();
  299. }
  300. else
  301. {
  302. delete this;
  303. }
  304. }
  305. juce_UseDebuggingNewOperator
  306. private:
  307. Image* image;
  308. uint32 lastTime;
  309. float alpha, alphaChangePerMs;
  310. float centreX, xChangePerMs;
  311. float centreY, yChangePerMs;
  312. float scale, scaleChangePerMs;
  313. FadeOutProxyComponent (const FadeOutProxyComponent&);
  314. const FadeOutProxyComponent& operator= (const FadeOutProxyComponent&);
  315. };
  316. void Component::fadeOutComponent (const int millisecondsToFade,
  317. const int deltaXToMove,
  318. const int deltaYToMove,
  319. const float scaleFactorAtEnd)
  320. {
  321. //xxx won't work for comps without parents
  322. if (isShowing() && millisecondsToFade > 0)
  323. new FadeOutProxyComponent (this, millisecondsToFade,
  324. deltaXToMove, deltaYToMove, scaleFactorAtEnd);
  325. setVisible (false);
  326. }
  327. //==============================================================================
  328. bool Component::isValidComponent() const throw()
  329. {
  330. return (this != 0) && isValidMessageListener();
  331. }
  332. void* Component::getWindowHandle() const throw()
  333. {
  334. const ComponentPeer* const peer = getPeer();
  335. if (peer != 0)
  336. return peer->getNativeHandle();
  337. return 0;
  338. }
  339. //==============================================================================
  340. void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo)
  341. {
  342. // if component methods are being called from threads other than the message
  343. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  344. checkMessageManagerIsLocked
  345. if (! isOpaque())
  346. styleWanted |= ComponentPeer::windowIsSemiTransparent;
  347. int currentStyleFlags = 0;
  348. // don't use getPeer(), so that we only get the peer that's specifically
  349. // for this comp, and not for one of its parents.
  350. ComponentPeer* peer = ComponentPeer::getPeerFor (this);
  351. if (peer != 0)
  352. currentStyleFlags = peer->getStyleFlags();
  353. if (styleWanted != currentStyleFlags || ! flags.hasHeavyweightPeerFlag)
  354. {
  355. const ComponentDeletionWatcher deletionChecker (this);
  356. #if JUCE_LINUX
  357. // it's wise to give the component a non-zero size before
  358. // putting it on the desktop, as X windows get confused by this, and
  359. // a (1, 1) minimum size is enforced here.
  360. setSize (jmax (1, getWidth()),
  361. jmax (1, getHeight()));
  362. #endif
  363. int x = 0, y = 0;
  364. relativePositionToGlobal (x, y);
  365. bool wasFullscreen = false;
  366. bool wasMinimised = false;
  367. ComponentBoundsConstrainer* currentConstainer = 0;
  368. Rectangle oldNonFullScreenBounds;
  369. if (peer != 0)
  370. {
  371. wasFullscreen = peer->isFullScreen();
  372. wasMinimised = peer->isMinimised();
  373. currentConstainer = peer->getConstrainer();
  374. oldNonFullScreenBounds = peer->getNonFullScreenBounds();
  375. removeFromDesktop();
  376. setTopLeftPosition (x, y);
  377. }
  378. if (parentComponent_ != 0)
  379. parentComponent_->removeChildComponent (this);
  380. if (! deletionChecker.hasBeenDeleted())
  381. {
  382. flags.hasHeavyweightPeerFlag = true;
  383. peer = createNewPeer (styleWanted, nativeWindowToAttachTo);
  384. Desktop::getInstance().addDesktopComponent (this);
  385. bounds_.setPosition (x, y);
  386. peer->setBounds (x, y, getWidth(), getHeight(), false);
  387. peer->setVisible (isVisible());
  388. if (wasFullscreen)
  389. {
  390. peer->setFullScreen (true);
  391. peer->setNonFullScreenBounds (oldNonFullScreenBounds);
  392. }
  393. if (wasMinimised)
  394. peer->setMinimised (true);
  395. if (isAlwaysOnTop())
  396. peer->setAlwaysOnTop (true);
  397. peer->setConstrainer (currentConstainer);
  398. repaint();
  399. }
  400. internalHierarchyChanged();
  401. }
  402. }
  403. void Component::removeFromDesktop()
  404. {
  405. // if component methods are being called from threads other than the message
  406. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  407. checkMessageManagerIsLocked
  408. if (flags.hasHeavyweightPeerFlag)
  409. {
  410. ComponentPeer* const peer = ComponentPeer::getPeerFor (this);
  411. flags.hasHeavyweightPeerFlag = false;
  412. jassert (peer != 0);
  413. delete peer;
  414. Desktop::getInstance().removeDesktopComponent (this);
  415. }
  416. }
  417. bool Component::isOnDesktop() const throw()
  418. {
  419. return flags.hasHeavyweightPeerFlag;
  420. }
  421. void Component::userTriedToCloseWindow()
  422. {
  423. /* This means that the user's trying to get rid of your window with the 'close window' system
  424. menu option (on windows) or possibly the task manager - you should really handle this
  425. and delete or hide your component in an appropriate way.
  426. If you want to ignore the event and don't want to trigger this assertion, just override
  427. this method and do nothing.
  428. */
  429. jassertfalse
  430. }
  431. void Component::minimisationStateChanged (bool)
  432. {
  433. }
  434. //==============================================================================
  435. void Component::setOpaque (const bool shouldBeOpaque) throw()
  436. {
  437. if (shouldBeOpaque != flags.opaqueFlag)
  438. {
  439. flags.opaqueFlag = shouldBeOpaque;
  440. if (flags.hasHeavyweightPeerFlag)
  441. {
  442. const ComponentPeer* const peer = ComponentPeer::getPeerFor (this);
  443. if (peer != 0)
  444. {
  445. // to make it recreate the heavyweight window
  446. addToDesktop (peer->getStyleFlags());
  447. }
  448. }
  449. repaint();
  450. }
  451. }
  452. bool Component::isOpaque() const throw()
  453. {
  454. return flags.opaqueFlag;
  455. }
  456. //==============================================================================
  457. void Component::setBufferedToImage (const bool shouldBeBuffered) throw()
  458. {
  459. if (shouldBeBuffered != flags.bufferToImageFlag)
  460. {
  461. deleteAndZero (bufferedImage_);
  462. flags.bufferToImageFlag = shouldBeBuffered;
  463. }
  464. }
  465. //==============================================================================
  466. void Component::toFront (const bool setAsForeground)
  467. {
  468. // if component methods are being called from threads other than the message
  469. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  470. checkMessageManagerIsLocked
  471. if (flags.hasHeavyweightPeerFlag)
  472. {
  473. ComponentPeer* const peer = getPeer();
  474. if (peer != 0)
  475. {
  476. peer->toFront (setAsForeground);
  477. if (setAsForeground && ! hasKeyboardFocus (true))
  478. grabKeyboardFocus();
  479. }
  480. }
  481. else if (parentComponent_ != 0)
  482. {
  483. if (parentComponent_->childComponentList_.getLast() != this)
  484. {
  485. const int index = parentComponent_->childComponentList_.indexOf (this);
  486. if (index >= 0)
  487. {
  488. int insertIndex = -1;
  489. if (! flags.alwaysOnTopFlag)
  490. {
  491. insertIndex = parentComponent_->childComponentList_.size() - 1;
  492. while (insertIndex > 0
  493. && parentComponent_->childComponentList_.getUnchecked (insertIndex)->isAlwaysOnTop())
  494. {
  495. --insertIndex;
  496. }
  497. }
  498. if (index != insertIndex)
  499. {
  500. parentComponent_->childComponentList_.move (index, insertIndex);
  501. sendFakeMouseMove();
  502. repaintParent();
  503. }
  504. }
  505. }
  506. if (setAsForeground)
  507. {
  508. internalBroughtToFront();
  509. grabKeyboardFocus();
  510. }
  511. }
  512. }
  513. void Component::toBehind (Component* const other)
  514. {
  515. if (other != 0)
  516. {
  517. // the two components must belong to the same parent..
  518. jassert (parentComponent_ == other->parentComponent_);
  519. if (parentComponent_ != 0)
  520. {
  521. const int index = parentComponent_->childComponentList_.indexOf (this);
  522. int otherIndex = parentComponent_->childComponentList_.indexOf (other);
  523. if (index >= 0
  524. && otherIndex >= 0
  525. && index != otherIndex - 1
  526. && other != this)
  527. {
  528. if (index < otherIndex)
  529. --otherIndex;
  530. parentComponent_->childComponentList_.move (index, otherIndex);
  531. sendFakeMouseMove();
  532. repaintParent();
  533. }
  534. }
  535. else if (isOnDesktop())
  536. {
  537. jassert (other->isOnDesktop());
  538. if (other->isOnDesktop())
  539. {
  540. ComponentPeer* const us = getPeer();
  541. ComponentPeer* const them = other->getPeer();
  542. jassert (us != 0 && them != 0);
  543. if (us != 0 && them != 0)
  544. us->toBehind (them);
  545. }
  546. }
  547. }
  548. }
  549. void Component::toBack()
  550. {
  551. if (isOnDesktop())
  552. {
  553. jassertfalse //xxx need to add this to native window
  554. }
  555. else if (parentComponent_ != 0
  556. && parentComponent_->childComponentList_.getFirst() != this)
  557. {
  558. const int index = parentComponent_->childComponentList_.indexOf (this);
  559. if (index > 0)
  560. {
  561. int insertIndex = 0;
  562. if (flags.alwaysOnTopFlag)
  563. {
  564. while (insertIndex < parentComponent_->childComponentList_.size()
  565. && ! parentComponent_->childComponentList_.getUnchecked (insertIndex)->isAlwaysOnTop())
  566. {
  567. ++insertIndex;
  568. }
  569. }
  570. if (index != insertIndex)
  571. {
  572. parentComponent_->childComponentList_.move (index, insertIndex);
  573. sendFakeMouseMove();
  574. repaintParent();
  575. }
  576. }
  577. }
  578. }
  579. void Component::setAlwaysOnTop (const bool shouldStayOnTop)
  580. {
  581. if (shouldStayOnTop != flags.alwaysOnTopFlag)
  582. {
  583. flags.alwaysOnTopFlag = shouldStayOnTop;
  584. if (isOnDesktop())
  585. {
  586. ComponentPeer* const peer = getPeer();
  587. jassert (peer != 0);
  588. if (peer != 0)
  589. {
  590. if (! peer->setAlwaysOnTop (shouldStayOnTop))
  591. {
  592. // some kinds of peer can't change their always-on-top status, so
  593. // for these, we'll need to create a new window
  594. const int oldFlags = peer->getStyleFlags();
  595. removeFromDesktop();
  596. addToDesktop (oldFlags);
  597. }
  598. }
  599. }
  600. if (shouldStayOnTop)
  601. toFront (false);
  602. internalHierarchyChanged();
  603. }
  604. }
  605. bool Component::isAlwaysOnTop() const throw()
  606. {
  607. return flags.alwaysOnTopFlag;
  608. }
  609. //==============================================================================
  610. int Component::proportionOfWidth (const float proportion) const throw()
  611. {
  612. return roundDoubleToInt (proportion * bounds_.getWidth());
  613. }
  614. int Component::proportionOfHeight (const float proportion) const throw()
  615. {
  616. return roundDoubleToInt (proportion * bounds_.getHeight());
  617. }
  618. int Component::getParentWidth() const throw()
  619. {
  620. return (parentComponent_ != 0) ? parentComponent_->getWidth()
  621. : getParentMonitorArea().getWidth();
  622. }
  623. int Component::getParentHeight() const throw()
  624. {
  625. return (parentComponent_ != 0) ? parentComponent_->getHeight()
  626. : getParentMonitorArea().getHeight();
  627. }
  628. int Component::getScreenX() const throw()
  629. {
  630. return (parentComponent_ != 0) ? parentComponent_->getScreenX() + getX()
  631. : (flags.hasHeavyweightPeerFlag ? getPeer()->getScreenX()
  632. : getX());
  633. }
  634. int Component::getScreenY() const throw()
  635. {
  636. return (parentComponent_ != 0) ? parentComponent_->getScreenY() + getY()
  637. : (flags.hasHeavyweightPeerFlag ? getPeer()->getScreenY()
  638. : getY());
  639. }
  640. void Component::relativePositionToGlobal (int& x, int& y) const throw()
  641. {
  642. const Component* c = this;
  643. do
  644. {
  645. if (c->flags.hasHeavyweightPeerFlag)
  646. {
  647. c->getPeer()->relativePositionToGlobal (x, y);
  648. break;
  649. }
  650. x += c->getX();
  651. y += c->getY();
  652. c = c->parentComponent_;
  653. }
  654. while (c != 0);
  655. }
  656. void Component::globalPositionToRelative (int& x, int& y) const throw()
  657. {
  658. if (flags.hasHeavyweightPeerFlag)
  659. {
  660. getPeer()->globalPositionToRelative (x, y);
  661. }
  662. else
  663. {
  664. if (parentComponent_ != 0)
  665. parentComponent_->globalPositionToRelative (x, y);
  666. x -= getX();
  667. y -= getY();
  668. }
  669. }
  670. void Component::relativePositionToOtherComponent (const Component* const targetComponent, int& x, int& y) const throw()
  671. {
  672. if (targetComponent != 0)
  673. {
  674. const Component* c = this;
  675. do
  676. {
  677. if (c == targetComponent)
  678. return;
  679. if (c->flags.hasHeavyweightPeerFlag)
  680. {
  681. c->getPeer()->relativePositionToGlobal (x, y);
  682. break;
  683. }
  684. x += c->getX();
  685. y += c->getY();
  686. c = c->parentComponent_;
  687. }
  688. while (c != 0);
  689. targetComponent->globalPositionToRelative (x, y);
  690. }
  691. }
  692. //==============================================================================
  693. void Component::setBounds (int x, int y, int w, int h)
  694. {
  695. // if component methods are being called from threads other than the message
  696. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  697. checkMessageManagerIsLocked
  698. if (w < 0) w = 0;
  699. if (h < 0) h = 0;
  700. const bool wasResized = (getWidth() != w || getHeight() != h);
  701. const bool wasMoved = (getX() != x || getY() != y);
  702. #ifdef JUCE_DEBUG
  703. // It's a very bad idea to try to resize a window during its paint() method!
  704. jassert (! (flags.isInsidePaintCall && wasResized && isOnDesktop()));
  705. #endif
  706. if (wasMoved || wasResized)
  707. {
  708. if (flags.visibleFlag)
  709. {
  710. // send a fake mouse move to trigger enter/exit messages if needed..
  711. sendFakeMouseMove();
  712. if (! flags.hasHeavyweightPeerFlag)
  713. repaintParent();
  714. }
  715. bounds_.setBounds (x, y, w, h);
  716. if (wasResized)
  717. repaint();
  718. else if (! flags.hasHeavyweightPeerFlag)
  719. repaintParent();
  720. if (flags.hasHeavyweightPeerFlag)
  721. {
  722. ComponentPeer* const peer = getPeer();
  723. if (peer != 0)
  724. {
  725. if (wasMoved && wasResized)
  726. peer->setBounds (getX(), getY(), getWidth(), getHeight(), false);
  727. else if (wasMoved)
  728. peer->setPosition (getX(), getY());
  729. else if (wasResized)
  730. peer->setSize (getWidth(), getHeight());
  731. }
  732. }
  733. sendMovedResizedMessages (wasMoved, wasResized);
  734. }
  735. }
  736. void Component::sendMovedResizedMessages (const bool wasMoved, const bool wasResized)
  737. {
  738. JUCE_TRY
  739. {
  740. if (wasMoved)
  741. moved();
  742. if (wasResized)
  743. {
  744. resized();
  745. for (int i = childComponentList_.size(); --i >= 0;)
  746. {
  747. childComponentList_.getUnchecked(i)->parentSizeChanged();
  748. i = jmin (i, childComponentList_.size());
  749. }
  750. }
  751. if (parentComponent_ != 0)
  752. parentComponent_->childBoundsChanged (this);
  753. if (componentListeners_ != 0)
  754. {
  755. const ComponentDeletionWatcher deletionChecker (this);
  756. for (int i = componentListeners_->size(); --i >= 0;)
  757. {
  758. ((ComponentListener*) componentListeners_->getUnchecked (i))
  759. ->componentMovedOrResized (*this, wasMoved, wasResized);
  760. if (deletionChecker.hasBeenDeleted())
  761. return;
  762. i = jmin (i, componentListeners_->size());
  763. }
  764. }
  765. }
  766. JUCE_CATCH_EXCEPTION
  767. }
  768. void Component::setSize (const int w, const int h)
  769. {
  770. setBounds (getX(), getY(), w, h);
  771. }
  772. void Component::setTopLeftPosition (const int x, const int y)
  773. {
  774. setBounds (x, y, getWidth(), getHeight());
  775. }
  776. void Component::setTopRightPosition (const int x, const int y)
  777. {
  778. setTopLeftPosition (x - getWidth(), y);
  779. }
  780. void Component::setBounds (const Rectangle& r)
  781. {
  782. setBounds (r.getX(),
  783. r.getY(),
  784. r.getWidth(),
  785. r.getHeight());
  786. }
  787. void Component::setBoundsRelative (const float x, const float y,
  788. const float w, const float h)
  789. {
  790. const int pw = getParentWidth();
  791. const int ph = getParentHeight();
  792. setBounds (roundFloatToInt (x * pw),
  793. roundFloatToInt (y * ph),
  794. roundFloatToInt (w * pw),
  795. roundFloatToInt (h * ph));
  796. }
  797. void Component::setCentrePosition (const int x, const int y)
  798. {
  799. setTopLeftPosition (x - getWidth() / 2,
  800. y - getHeight() / 2);
  801. }
  802. void Component::setCentreRelative (const float x, const float y)
  803. {
  804. setCentrePosition (roundFloatToInt (getParentWidth() * x),
  805. roundFloatToInt (getParentHeight() * y));
  806. }
  807. void Component::centreWithSize (const int width, const int height)
  808. {
  809. setBounds ((getParentWidth() - width) / 2,
  810. (getParentHeight() - height) / 2,
  811. width,
  812. height);
  813. }
  814. void Component::setBoundsInset (const BorderSize& borders)
  815. {
  816. setBounds (borders.getLeft(),
  817. borders.getTop(),
  818. getParentWidth() - (borders.getLeftAndRight()),
  819. getParentHeight() - (borders.getTopAndBottom()));
  820. }
  821. void Component::setBoundsToFit (int x, int y, int width, int height,
  822. const Justification& justification,
  823. const bool onlyReduceInSize)
  824. {
  825. // it's no good calling this method unless both the component and
  826. // target rectangle have a finite size.
  827. jassert (getWidth() > 0 && getHeight() > 0 && width > 0 && height > 0);
  828. if (getWidth() > 0 && getHeight() > 0
  829. && width > 0 && height > 0)
  830. {
  831. int newW, newH;
  832. if (onlyReduceInSize && getWidth() <= width && getHeight() <= height)
  833. {
  834. newW = getWidth();
  835. newH = getHeight();
  836. }
  837. else
  838. {
  839. const double imageRatio = getHeight() / (double) getWidth();
  840. const double targetRatio = height / (double) width;
  841. if (imageRatio <= targetRatio)
  842. {
  843. newW = width;
  844. newH = jmin (height, roundDoubleToInt (newW * imageRatio));
  845. }
  846. else
  847. {
  848. newH = height;
  849. newW = jmin (width, roundDoubleToInt (newH / imageRatio));
  850. }
  851. }
  852. if (newW > 0 && newH > 0)
  853. {
  854. int newX, newY;
  855. justification.applyToRectangle (newX, newY, newW, newH,
  856. x, y, width, height);
  857. setBounds (newX, newY, newW, newH);
  858. }
  859. }
  860. }
  861. //==============================================================================
  862. bool Component::hitTest (int x, int y)
  863. {
  864. if (! flags.ignoresMouseClicksFlag)
  865. return true;
  866. if (flags.allowChildMouseClicksFlag)
  867. {
  868. for (int i = getNumChildComponents(); --i >= 0;)
  869. {
  870. Component* const c = getChildComponent (i);
  871. if (c->isVisible()
  872. && c->bounds_.contains (x, y)
  873. && c->hitTest (x - c->getX(),
  874. y - c->getY()))
  875. {
  876. return true;
  877. }
  878. }
  879. }
  880. return false;
  881. }
  882. void Component::setInterceptsMouseClicks (const bool allowClicks,
  883. const bool allowClicksOnChildComponents) throw()
  884. {
  885. flags.ignoresMouseClicksFlag = ! allowClicks;
  886. flags.allowChildMouseClicksFlag = allowClicksOnChildComponents;
  887. }
  888. void Component::getInterceptsMouseClicks (bool& allowsClicksOnThisComponent,
  889. bool& allowsClicksOnChildComponents) const throw()
  890. {
  891. allowsClicksOnThisComponent = ! flags.ignoresMouseClicksFlag;
  892. allowsClicksOnChildComponents = flags.allowChildMouseClicksFlag;
  893. }
  894. bool Component::contains (const int x, const int y)
  895. {
  896. if (((unsigned int) x) < (unsigned int) getWidth()
  897. && ((unsigned int) y) < (unsigned int) getHeight()
  898. && hitTest (x, y))
  899. {
  900. if (parentComponent_ != 0)
  901. {
  902. return parentComponent_->contains (x + getX(),
  903. y + getY());
  904. }
  905. else if (flags.hasHeavyweightPeerFlag)
  906. {
  907. const ComponentPeer* const peer = getPeer();
  908. if (peer != 0)
  909. return peer->contains (x, y, true);
  910. }
  911. }
  912. return false;
  913. }
  914. bool Component::reallyContains (int x, int y, const bool returnTrueIfWithinAChild)
  915. {
  916. if (! contains (x, y))
  917. return false;
  918. Component* p = this;
  919. while (p->parentComponent_ != 0)
  920. {
  921. x += p->getX();
  922. y += p->getY();
  923. p = p->parentComponent_;
  924. }
  925. const Component* const c = p->getComponentAt (x, y);
  926. return (c == this) || (returnTrueIfWithinAChild && isParentOf (c));
  927. }
  928. Component* Component::getComponentAt (const int x, const int y)
  929. {
  930. if (flags.visibleFlag
  931. && ((unsigned int) x) < (unsigned int) getWidth()
  932. && ((unsigned int) y) < (unsigned int) getHeight()
  933. && hitTest (x, y))
  934. {
  935. for (int i = childComponentList_.size(); --i >= 0;)
  936. {
  937. Component* const child = childComponentList_.getUnchecked(i);
  938. Component* const c = child->getComponentAt (x - child->getX(),
  939. y - child->getY());
  940. if (c != 0)
  941. return c;
  942. }
  943. return this;
  944. }
  945. return 0;
  946. }
  947. //==============================================================================
  948. void Component::addChildComponent (Component* const child, int zOrder)
  949. {
  950. // if component methods are being called from threads other than the message
  951. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  952. checkMessageManagerIsLocked
  953. if (child != 0 && child->parentComponent_ != this)
  954. {
  955. if (child->parentComponent_ != 0)
  956. child->parentComponent_->removeChildComponent (child);
  957. else
  958. child->removeFromDesktop();
  959. child->parentComponent_ = this;
  960. if (child->isVisible())
  961. child->repaintParent();
  962. if (! child->isAlwaysOnTop())
  963. {
  964. if (zOrder < 0 || zOrder > childComponentList_.size())
  965. zOrder = childComponentList_.size();
  966. while (zOrder > 0)
  967. {
  968. if (! childComponentList_.getUnchecked (zOrder - 1)->isAlwaysOnTop())
  969. break;
  970. --zOrder;
  971. }
  972. }
  973. childComponentList_.insert (zOrder, child);
  974. child->internalHierarchyChanged();
  975. internalChildrenChanged();
  976. }
  977. }
  978. void Component::addAndMakeVisible (Component* const child, int zOrder)
  979. {
  980. if (child != 0)
  981. {
  982. child->setVisible (true);
  983. addChildComponent (child, zOrder);
  984. }
  985. }
  986. void Component::removeChildComponent (Component* const child)
  987. {
  988. removeChildComponent (childComponentList_.indexOf (child));
  989. }
  990. Component* Component::removeChildComponent (const int index)
  991. {
  992. // if component methods are being called from threads other than the message
  993. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  994. checkMessageManagerIsLocked
  995. Component* const child = childComponentList_ [index];
  996. if (child != 0)
  997. {
  998. sendFakeMouseMove();
  999. child->repaintParent();
  1000. childComponentList_.remove (index);
  1001. child->parentComponent_ = 0;
  1002. JUCE_TRY
  1003. {
  1004. if ((currentlyFocusedComponent == child)
  1005. || child->isParentOf (currentlyFocusedComponent))
  1006. {
  1007. // get rid first to force the grabKeyboardFocus to change to us.
  1008. giveAwayFocus();
  1009. grabKeyboardFocus();
  1010. }
  1011. }
  1012. #if JUCE_CATCH_UNHANDLED_EXCEPTIONS
  1013. catch (const std::exception& e)
  1014. {
  1015. currentlyFocusedComponent = 0;
  1016. Desktop::getInstance().triggerFocusCallback();
  1017. JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__);
  1018. }
  1019. catch (...)
  1020. {
  1021. currentlyFocusedComponent = 0;
  1022. Desktop::getInstance().triggerFocusCallback();
  1023. JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__);
  1024. }
  1025. #endif
  1026. child->internalHierarchyChanged();
  1027. internalChildrenChanged();
  1028. }
  1029. return child;
  1030. }
  1031. //==============================================================================
  1032. void Component::removeAllChildren()
  1033. {
  1034. for (int i = childComponentList_.size(); --i >= 0;)
  1035. removeChildComponent (i);
  1036. }
  1037. void Component::deleteAllChildren()
  1038. {
  1039. for (int i = childComponentList_.size(); --i >= 0;)
  1040. delete (removeChildComponent (i));
  1041. }
  1042. //==============================================================================
  1043. int Component::getNumChildComponents() const throw()
  1044. {
  1045. return childComponentList_.size();
  1046. }
  1047. Component* Component::getChildComponent (const int index) const throw()
  1048. {
  1049. return childComponentList_ [index];
  1050. }
  1051. int Component::getIndexOfChildComponent (const Component* const child) const throw()
  1052. {
  1053. return childComponentList_.indexOf (const_cast <Component*> (child));
  1054. }
  1055. Component* Component::getTopLevelComponent() const throw()
  1056. {
  1057. const Component* comp = this;
  1058. while (comp->parentComponent_ != 0)
  1059. comp = comp->parentComponent_;
  1060. return (Component*) comp;
  1061. }
  1062. bool Component::isParentOf (const Component* possibleChild) const throw()
  1063. {
  1064. while (possibleChild->isValidComponent())
  1065. {
  1066. possibleChild = possibleChild->parentComponent_;
  1067. if (possibleChild == this)
  1068. return true;
  1069. }
  1070. return false;
  1071. }
  1072. //==============================================================================
  1073. void Component::parentHierarchyChanged()
  1074. {
  1075. }
  1076. void Component::childrenChanged()
  1077. {
  1078. }
  1079. void Component::internalChildrenChanged()
  1080. {
  1081. const ComponentDeletionWatcher deletionChecker (this);
  1082. const bool hasListeners = componentListeners_ != 0;
  1083. childrenChanged();
  1084. if (hasListeners)
  1085. {
  1086. if (deletionChecker.hasBeenDeleted())
  1087. return;
  1088. for (int i = componentListeners_->size(); --i >= 0;)
  1089. {
  1090. ((ComponentListener*) componentListeners_->getUnchecked (i))
  1091. ->componentChildrenChanged (*this);
  1092. if (deletionChecker.hasBeenDeleted())
  1093. return;
  1094. i = jmin (i, componentListeners_->size());
  1095. }
  1096. }
  1097. }
  1098. void Component::internalHierarchyChanged()
  1099. {
  1100. parentHierarchyChanged();
  1101. const ComponentDeletionWatcher deletionChecker (this);
  1102. if (componentListeners_ != 0)
  1103. {
  1104. for (int i = componentListeners_->size(); --i >= 0;)
  1105. {
  1106. ((ComponentListener*) componentListeners_->getUnchecked (i))
  1107. ->componentParentHierarchyChanged (*this);
  1108. if (deletionChecker.hasBeenDeleted())
  1109. return;
  1110. i = jmin (i, componentListeners_->size());
  1111. }
  1112. }
  1113. for (int i = childComponentList_.size(); --i >= 0;)
  1114. {
  1115. childComponentList_.getUnchecked (i)->internalHierarchyChanged();
  1116. // you really shouldn't delete the parent component during a callback telling you
  1117. // that it's changed..
  1118. jassert (! deletionChecker.hasBeenDeleted());
  1119. if (deletionChecker.hasBeenDeleted())
  1120. return;
  1121. i = jmin (i, childComponentList_.size());
  1122. }
  1123. }
  1124. //==============================================================================
  1125. void* Component::runModalLoopCallback (void* userData)
  1126. {
  1127. return (void*) (pointer_sized_int) ((Component*) userData)->runModalLoop();
  1128. }
  1129. int Component::runModalLoop()
  1130. {
  1131. if (! MessageManager::getInstance()->isThisTheMessageThread())
  1132. {
  1133. // use a callback so this can be called from non-gui threads
  1134. return (int) (pointer_sized_int)
  1135. MessageManager::getInstance()
  1136. ->callFunctionOnMessageThread (&runModalLoopCallback, (void*) this);
  1137. }
  1138. Component* const prevFocused = getCurrentlyFocusedComponent();
  1139. ComponentDeletionWatcher* deletionChecker = 0;
  1140. if (prevFocused != 0)
  1141. deletionChecker = new ComponentDeletionWatcher (prevFocused);
  1142. if (! isCurrentlyModal())
  1143. enterModalState();
  1144. JUCE_TRY
  1145. {
  1146. while (flags.currentlyModalFlag && flags.visibleFlag)
  1147. {
  1148. if (! MessageManager::getInstance()->runDispatchLoopUntil (20))
  1149. break;
  1150. // check whether this component was deleted during the last message
  1151. if (! isValidMessageListener())
  1152. break;
  1153. }
  1154. }
  1155. #if JUCE_CATCH_UNHANDLED_EXCEPTIONS
  1156. catch (const std::exception& e)
  1157. {
  1158. JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__);
  1159. return 0;
  1160. }
  1161. catch (...)
  1162. {
  1163. JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__);
  1164. return 0;
  1165. }
  1166. #endif
  1167. const int modalIndex = modalComponentReturnValueKeys.indexOf (this);
  1168. int returnValue = 0;
  1169. if (modalIndex >= 0)
  1170. {
  1171. modalComponentReturnValueKeys.remove (modalIndex);
  1172. returnValue = modalReturnValues.remove (modalIndex);
  1173. }
  1174. modalComponentStack.removeValue (this);
  1175. if (deletionChecker != 0)
  1176. {
  1177. if (! deletionChecker->hasBeenDeleted())
  1178. prevFocused->grabKeyboardFocus();
  1179. delete deletionChecker;
  1180. }
  1181. return returnValue;
  1182. }
  1183. void Component::enterModalState (const bool takeKeyboardFocus)
  1184. {
  1185. // if component methods are being called from threads other than the message
  1186. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  1187. checkMessageManagerIsLocked
  1188. // Check for an attempt to make a component modal when it already is!
  1189. // This can cause nasty problems..
  1190. jassert (! flags.currentlyModalFlag);
  1191. if (! isCurrentlyModal())
  1192. {
  1193. modalComponentStack.add (this);
  1194. modalComponentReturnValueKeys.add (this);
  1195. modalReturnValues.add (0);
  1196. flags.currentlyModalFlag = true;
  1197. setVisible (true);
  1198. if (takeKeyboardFocus)
  1199. grabKeyboardFocus();
  1200. }
  1201. }
  1202. void Component::exitModalState (const int returnValue)
  1203. {
  1204. if (isCurrentlyModal())
  1205. {
  1206. if (MessageManager::getInstance()->isThisTheMessageThread())
  1207. {
  1208. const int modalIndex = modalComponentReturnValueKeys.indexOf (this);
  1209. if (modalIndex >= 0)
  1210. {
  1211. modalReturnValues.set (modalIndex, returnValue);
  1212. }
  1213. else
  1214. {
  1215. modalComponentReturnValueKeys.add (this);
  1216. modalReturnValues.add (returnValue);
  1217. }
  1218. modalComponentStack.removeValue (this);
  1219. flags.currentlyModalFlag = false;
  1220. bringModalComponentToFront();
  1221. }
  1222. else
  1223. {
  1224. postMessage (new Message (exitModalStateMessage, returnValue, 0, 0));
  1225. }
  1226. }
  1227. }
  1228. bool Component::isCurrentlyModal() const throw()
  1229. {
  1230. return flags.currentlyModalFlag
  1231. && getCurrentlyModalComponent() == this;
  1232. }
  1233. bool Component::isCurrentlyBlockedByAnotherModalComponent() const throw()
  1234. {
  1235. Component* const mc = getCurrentlyModalComponent();
  1236. return mc != 0
  1237. && mc != this
  1238. && (! mc->isParentOf (this))
  1239. && ! mc->canModalEventBeSentToComponent (this);
  1240. }
  1241. int JUCE_CALLTYPE Component::getNumCurrentlyModalComponents() throw()
  1242. {
  1243. return modalComponentStack.size();
  1244. }
  1245. Component* JUCE_CALLTYPE Component::getCurrentlyModalComponent (int index) throw()
  1246. {
  1247. Component* const c = (Component*) (modalComponentStack [modalComponentStack.size() - index - 1]);
  1248. return c->isValidComponent() ? c : 0;
  1249. }
  1250. void Component::bringModalComponentToFront()
  1251. {
  1252. ComponentPeer* lastOne = 0;
  1253. for (int i = 0; i < getNumCurrentlyModalComponents(); ++i)
  1254. {
  1255. Component* const c = getCurrentlyModalComponent (i);
  1256. if (c == 0)
  1257. break;
  1258. ComponentPeer* peer = c->getPeer();
  1259. if (peer != 0 && peer != lastOne)
  1260. {
  1261. if (lastOne == 0)
  1262. {
  1263. peer->toFront (true);
  1264. peer->grabFocus();
  1265. }
  1266. else
  1267. peer->toBehind (lastOne);
  1268. lastOne = peer;
  1269. }
  1270. }
  1271. }
  1272. //==============================================================================
  1273. void Component::setBroughtToFrontOnMouseClick (const bool shouldBeBroughtToFront) throw()
  1274. {
  1275. flags.bringToFrontOnClickFlag = shouldBeBroughtToFront;
  1276. }
  1277. bool Component::isBroughtToFrontOnMouseClick() const throw()
  1278. {
  1279. return flags.bringToFrontOnClickFlag;
  1280. }
  1281. //==============================================================================
  1282. void Component::setMouseCursor (const MouseCursor& cursor) throw()
  1283. {
  1284. cursor_ = cursor;
  1285. if (flags.visibleFlag)
  1286. {
  1287. int mx, my;
  1288. getMouseXYRelative (mx, my);
  1289. if (flags.draggingFlag || reallyContains (mx, my, false))
  1290. {
  1291. internalUpdateMouseCursor (false);
  1292. }
  1293. }
  1294. }
  1295. const MouseCursor Component::getMouseCursor()
  1296. {
  1297. return cursor_;
  1298. }
  1299. void Component::updateMouseCursor() const throw()
  1300. {
  1301. sendFakeMouseMove();
  1302. }
  1303. void Component::internalUpdateMouseCursor (bool forcedUpdate) throw()
  1304. {
  1305. ComponentPeer* const peer = getPeer();
  1306. if (peer != 0)
  1307. {
  1308. MouseCursor mc (getLookAndFeel().getMouseCursorFor (*this));
  1309. if (isUnboundedMouseModeOn && (unboundedMouseOffsetX != 0
  1310. || unboundedMouseOffsetY != 0
  1311. || ! isCursorVisibleUntilOffscreen))
  1312. {
  1313. mc = MouseCursor::NoCursor;
  1314. forcedUpdate = true;
  1315. }
  1316. static void* currentCursorHandle = 0;
  1317. if (forcedUpdate || mc.getHandle() != currentCursorHandle)
  1318. {
  1319. currentCursorHandle = mc.getHandle();
  1320. mc.showInWindow (peer);
  1321. }
  1322. }
  1323. }
  1324. //==============================================================================
  1325. void Component::setRepaintsOnMouseActivity (const bool shouldRepaint) throw()
  1326. {
  1327. flags.repaintOnMouseActivityFlag = shouldRepaint;
  1328. }
  1329. //==============================================================================
  1330. void Component::repaintParent() throw()
  1331. {
  1332. if (flags.visibleFlag)
  1333. internalRepaint (0, 0, getWidth(), getHeight());
  1334. }
  1335. void Component::repaint() throw()
  1336. {
  1337. repaint (0, 0, getWidth(), getHeight());
  1338. }
  1339. void Component::repaint (const int x, const int y,
  1340. const int w, const int h) throw()
  1341. {
  1342. deleteAndZero (bufferedImage_);
  1343. if (flags.visibleFlag)
  1344. internalRepaint (x, y, w, h);
  1345. }
  1346. void Component::internalRepaint (int x, int y, int w, int h)
  1347. {
  1348. // if component methods are being called from threads other than the message
  1349. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  1350. checkMessageManagerIsLocked
  1351. if (x < 0)
  1352. {
  1353. w += x;
  1354. x = 0;
  1355. }
  1356. if (x + w > getWidth())
  1357. w = getWidth() - x;
  1358. if (w > 0)
  1359. {
  1360. if (y < 0)
  1361. {
  1362. h += y;
  1363. y = 0;
  1364. }
  1365. if (y + h > getHeight())
  1366. h = getHeight() - y;
  1367. if (h > 0)
  1368. {
  1369. if (parentComponent_ != 0)
  1370. {
  1371. x += getX();
  1372. y += getY();
  1373. if (parentComponent_->flags.visibleFlag)
  1374. parentComponent_->internalRepaint (x, y, w, h);
  1375. }
  1376. else if (flags.hasHeavyweightPeerFlag)
  1377. {
  1378. ComponentPeer* const peer = getPeer();
  1379. if (peer != 0)
  1380. peer->repaint (x, y, w, h);
  1381. }
  1382. }
  1383. }
  1384. }
  1385. //==============================================================================
  1386. void Component::paintEntireComponent (Graphics& originalContext)
  1387. {
  1388. jassert (! originalContext.isClipEmpty());
  1389. #ifdef JUCE_DEBUG
  1390. flags.isInsidePaintCall = true;
  1391. #endif
  1392. Graphics* g = &originalContext;
  1393. Image* effectImage = 0;
  1394. if (effect_ != 0)
  1395. {
  1396. effectImage = Image::createNativeImage (flags.opaqueFlag ? Image::RGB : Image::ARGB,
  1397. getWidth(), getHeight(),
  1398. ! flags.opaqueFlag);
  1399. g = new Graphics (*effectImage);
  1400. }
  1401. g->saveState();
  1402. clipObscuredRegions (*g, g->getClipBounds(), 0, 0);
  1403. if (! g->isClipEmpty())
  1404. {
  1405. if (bufferedImage_ != 0)
  1406. {
  1407. g->setColour (Colours::black);
  1408. g->drawImageAt (bufferedImage_, 0, 0);
  1409. }
  1410. else
  1411. {
  1412. if (flags.bufferToImageFlag)
  1413. {
  1414. if (bufferedImage_ == 0)
  1415. {
  1416. bufferedImage_ = Image::createNativeImage (flags.opaqueFlag ? Image::RGB : Image::ARGB,
  1417. getWidth(), getHeight(), ! flags.opaqueFlag);
  1418. Graphics imG (*bufferedImage_);
  1419. paint (imG);
  1420. }
  1421. g->setColour (Colours::black);
  1422. g->drawImageAt (bufferedImage_, 0, 0);
  1423. }
  1424. else
  1425. {
  1426. paint (*g);
  1427. g->resetToDefaultState();
  1428. }
  1429. }
  1430. }
  1431. g->restoreState();
  1432. for (int i = 0; i < childComponentList_.size(); ++i)
  1433. {
  1434. Component* const child = childComponentList_.getUnchecked (i);
  1435. if (child->isVisible())
  1436. {
  1437. g->saveState();
  1438. if (g->reduceClipRegion (child->getX(), child->getY(),
  1439. child->getWidth(), child->getHeight()))
  1440. {
  1441. for (int j = i + 1; j < childComponentList_.size(); ++j)
  1442. {
  1443. const Component* const sibling = childComponentList_.getUnchecked (j);
  1444. if (sibling->flags.opaqueFlag && sibling->isVisible())
  1445. g->excludeClipRegion (sibling->getX(), sibling->getY(),
  1446. sibling->getWidth(), sibling->getHeight());
  1447. }
  1448. if (! g->isClipEmpty())
  1449. {
  1450. g->setOrigin (child->getX(), child->getY());
  1451. child->paintEntireComponent (*g);
  1452. }
  1453. }
  1454. g->restoreState();
  1455. }
  1456. }
  1457. JUCE_TRY
  1458. {
  1459. g->saveState();
  1460. paintOverChildren (*g);
  1461. g->restoreState();
  1462. }
  1463. JUCE_CATCH_EXCEPTION
  1464. if (effect_ != 0)
  1465. {
  1466. delete g;
  1467. effect_->applyEffect (*effectImage, originalContext);
  1468. delete effectImage;
  1469. }
  1470. #ifdef JUCE_DEBUG
  1471. flags.isInsidePaintCall = false;
  1472. #endif
  1473. }
  1474. //==============================================================================
  1475. Image* Component::createComponentSnapshot (const Rectangle& areaToGrab,
  1476. const bool clipImageToComponentBounds)
  1477. {
  1478. Rectangle r (areaToGrab);
  1479. if (clipImageToComponentBounds)
  1480. r = r.getIntersection (Rectangle (0, 0, getWidth(), getHeight()));
  1481. Image* const componentImage = Image::createNativeImage (flags.opaqueFlag ? Image::RGB : Image::ARGB,
  1482. jmax (1, r.getWidth()),
  1483. jmax (1, r.getHeight()),
  1484. true);
  1485. Graphics imageContext (*componentImage);
  1486. imageContext.setOrigin (-r.getX(),
  1487. -r.getY());
  1488. paintEntireComponent (imageContext);
  1489. return componentImage;
  1490. }
  1491. void Component::setComponentEffect (ImageEffectFilter* const effect)
  1492. {
  1493. if (effect_ != effect)
  1494. {
  1495. effect_ = effect;
  1496. repaint();
  1497. }
  1498. }
  1499. //==============================================================================
  1500. LookAndFeel& Component::getLookAndFeel() const throw()
  1501. {
  1502. const Component* c = this;
  1503. do
  1504. {
  1505. if (c->lookAndFeel_ != 0)
  1506. return *(c->lookAndFeel_);
  1507. c = c->parentComponent_;
  1508. }
  1509. while (c != 0);
  1510. return LookAndFeel::getDefaultLookAndFeel();
  1511. }
  1512. void Component::setLookAndFeel (LookAndFeel* const newLookAndFeel)
  1513. {
  1514. if (lookAndFeel_ != newLookAndFeel)
  1515. {
  1516. lookAndFeel_ = newLookAndFeel;
  1517. sendLookAndFeelChange();
  1518. }
  1519. }
  1520. void Component::lookAndFeelChanged()
  1521. {
  1522. }
  1523. void Component::sendLookAndFeelChange()
  1524. {
  1525. repaint();
  1526. lookAndFeelChanged();
  1527. // (it's not a great idea to do anything that would delete this component
  1528. // during the lookAndFeelChanged() callback)
  1529. jassert (isValidComponent());
  1530. const ComponentDeletionWatcher deletionChecker (this);
  1531. for (int i = childComponentList_.size(); --i >= 0;)
  1532. {
  1533. childComponentList_.getUnchecked (i)->sendLookAndFeelChange();
  1534. if (deletionChecker.hasBeenDeleted())
  1535. return;
  1536. i = jmin (i, childComponentList_.size());
  1537. }
  1538. }
  1539. static const String getColourPropertyName (const int colourId) throw()
  1540. {
  1541. String s;
  1542. s.preallocateStorage (18);
  1543. s << T("jcclr_") << colourId;
  1544. return s;
  1545. }
  1546. const Colour Component::findColour (const int colourId, const bool inheritFromParent) const throw()
  1547. {
  1548. const String customColour (getComponentProperty (getColourPropertyName (colourId),
  1549. inheritFromParent,
  1550. String::empty));
  1551. if (customColour.isNotEmpty())
  1552. return Colour (customColour.getIntValue());
  1553. return getLookAndFeel().findColour (colourId);
  1554. }
  1555. bool Component::isColourSpecified (const int colourId) const throw()
  1556. {
  1557. return getComponentProperty (getColourPropertyName (colourId),
  1558. false,
  1559. String::empty).isNotEmpty();
  1560. }
  1561. void Component::removeColour (const int colourId)
  1562. {
  1563. if (isColourSpecified (colourId))
  1564. {
  1565. removeComponentProperty (getColourPropertyName (colourId));
  1566. colourChanged();
  1567. }
  1568. }
  1569. void Component::setColour (const int colourId, const Colour& colour)
  1570. {
  1571. const String colourName (getColourPropertyName (colourId));
  1572. const String customColour (getComponentProperty (colourName, false, String::empty));
  1573. if (customColour.isEmpty() || Colour (customColour.getIntValue()) != colour)
  1574. {
  1575. setComponentProperty (colourName, colour);
  1576. colourChanged();
  1577. }
  1578. }
  1579. void Component::copyAllExplicitColoursTo (Component& target) const throw()
  1580. {
  1581. if (propertySet_ != 0)
  1582. {
  1583. const StringPairArray& props = propertySet_->getAllProperties();
  1584. const StringArray& keys = props.getAllKeys();
  1585. for (int i = 0; i < keys.size(); ++i)
  1586. {
  1587. if (keys[i].startsWith (T("jcclr_")))
  1588. {
  1589. target.setComponentProperty (keys[i],
  1590. props.getAllValues() [i]);
  1591. }
  1592. }
  1593. target.colourChanged();
  1594. }
  1595. }
  1596. void Component::colourChanged()
  1597. {
  1598. }
  1599. //==============================================================================
  1600. const Rectangle Component::getUnclippedArea() const
  1601. {
  1602. int x = 0, y = 0, w = getWidth(), h = getHeight();
  1603. Component* p = parentComponent_;
  1604. int px = getX();
  1605. int py = getY();
  1606. while (p != 0)
  1607. {
  1608. if (! Rectangle::intersectRectangles (x, y, w, h, -px, -py, p->getWidth(), p->getHeight()))
  1609. return Rectangle();
  1610. px += p->getX();
  1611. py += p->getY();
  1612. p = p->parentComponent_;
  1613. }
  1614. return Rectangle (x, y, w, h);
  1615. }
  1616. void Component::clipObscuredRegions (Graphics& g, const Rectangle& clipRect,
  1617. const int deltaX, const int deltaY) const throw()
  1618. {
  1619. for (int i = childComponentList_.size(); --i >= 0;)
  1620. {
  1621. const Component* const c = childComponentList_.getUnchecked(i);
  1622. if (c->isVisible())
  1623. {
  1624. Rectangle newClip (clipRect.getIntersection (c->bounds_));
  1625. if (! newClip.isEmpty())
  1626. {
  1627. if (c->isOpaque())
  1628. {
  1629. g.excludeClipRegion (deltaX + newClip.getX(),
  1630. deltaY + newClip.getY(),
  1631. newClip.getWidth(),
  1632. newClip.getHeight());
  1633. }
  1634. else
  1635. {
  1636. newClip.translate (-c->getX(), -c->getY());
  1637. c->clipObscuredRegions (g, newClip,
  1638. c->getX() + deltaX,
  1639. c->getY() + deltaY);
  1640. }
  1641. }
  1642. }
  1643. }
  1644. }
  1645. void Component::getVisibleArea (RectangleList& result,
  1646. const bool includeSiblings) const
  1647. {
  1648. result.clear();
  1649. const Rectangle unclipped (getUnclippedArea());
  1650. if (! unclipped.isEmpty())
  1651. {
  1652. result.add (unclipped);
  1653. if (includeSiblings)
  1654. {
  1655. const Component* const c = getTopLevelComponent();
  1656. int x = 0, y = 0;
  1657. c->relativePositionToOtherComponent (this, x, y);
  1658. c->subtractObscuredRegions (result, x, y,
  1659. Rectangle (0, 0, c->getWidth(), c->getHeight()),
  1660. this);
  1661. }
  1662. subtractObscuredRegions (result, 0, 0, unclipped, 0);
  1663. result.consolidate();
  1664. }
  1665. }
  1666. void Component::subtractObscuredRegions (RectangleList& result,
  1667. const int deltaX,
  1668. const int deltaY,
  1669. const Rectangle& clipRect,
  1670. const Component* const compToAvoid) const throw()
  1671. {
  1672. for (int i = childComponentList_.size(); --i >= 0;)
  1673. {
  1674. const Component* const c = childComponentList_.getUnchecked(i);
  1675. if (c != compToAvoid && c->isVisible())
  1676. {
  1677. if (c->isOpaque())
  1678. {
  1679. Rectangle childBounds (c->bounds_.getIntersection (clipRect));
  1680. childBounds.translate (deltaX, deltaY);
  1681. result.subtract (childBounds);
  1682. }
  1683. else
  1684. {
  1685. Rectangle newClip (clipRect.getIntersection (c->bounds_));
  1686. newClip.translate (-c->getX(), -c->getY());
  1687. c->subtractObscuredRegions (result,
  1688. c->getX() + deltaX,
  1689. c->getY() + deltaY,
  1690. newClip,
  1691. compToAvoid);
  1692. }
  1693. }
  1694. }
  1695. }
  1696. //==============================================================================
  1697. void Component::mouseEnter (const MouseEvent&)
  1698. {
  1699. // base class does nothing
  1700. }
  1701. void Component::mouseExit (const MouseEvent&)
  1702. {
  1703. // base class does nothing
  1704. }
  1705. void Component::mouseDown (const MouseEvent&)
  1706. {
  1707. // base class does nothing
  1708. }
  1709. void Component::mouseUp (const MouseEvent&)
  1710. {
  1711. // base class does nothing
  1712. }
  1713. void Component::mouseDrag (const MouseEvent&)
  1714. {
  1715. // base class does nothing
  1716. }
  1717. void Component::mouseMove (const MouseEvent&)
  1718. {
  1719. // base class does nothing
  1720. }
  1721. void Component::mouseDoubleClick (const MouseEvent&)
  1722. {
  1723. // base class does nothing
  1724. }
  1725. void Component::mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY)
  1726. {
  1727. // the base class just passes this event up to its parent..
  1728. if (parentComponent_ != 0)
  1729. parentComponent_->mouseWheelMove (e.getEventRelativeTo (parentComponent_),
  1730. wheelIncrementX, wheelIncrementY);
  1731. }
  1732. //==============================================================================
  1733. void Component::resized()
  1734. {
  1735. // base class does nothing
  1736. }
  1737. void Component::moved()
  1738. {
  1739. // base class does nothing
  1740. }
  1741. void Component::childBoundsChanged (Component*)
  1742. {
  1743. // base class does nothing
  1744. }
  1745. void Component::parentSizeChanged()
  1746. {
  1747. // base class does nothing
  1748. }
  1749. void Component::addComponentListener (ComponentListener* const newListener) throw()
  1750. {
  1751. if (componentListeners_ == 0)
  1752. componentListeners_ = new VoidArray (4);
  1753. componentListeners_->addIfNotAlreadyThere (newListener);
  1754. }
  1755. void Component::removeComponentListener (ComponentListener* const listenerToRemove) throw()
  1756. {
  1757. jassert (isValidComponent());
  1758. if (componentListeners_ != 0)
  1759. componentListeners_->removeValue (listenerToRemove);
  1760. }
  1761. //==============================================================================
  1762. void Component::inputAttemptWhenModal()
  1763. {
  1764. bringModalComponentToFront();
  1765. getLookAndFeel().playAlertSound();
  1766. }
  1767. bool Component::canModalEventBeSentToComponent (const Component*)
  1768. {
  1769. return false;
  1770. }
  1771. void Component::internalModalInputAttempt()
  1772. {
  1773. Component* const current = getCurrentlyModalComponent();
  1774. if (current != 0)
  1775. current->inputAttemptWhenModal();
  1776. }
  1777. //==============================================================================
  1778. void Component::paint (Graphics&)
  1779. {
  1780. // all painting is done in the subclasses
  1781. jassert (! isOpaque()); // if your component's opaque, you've gotta paint it!
  1782. }
  1783. void Component::paintOverChildren (Graphics&)
  1784. {
  1785. // all painting is done in the subclasses
  1786. }
  1787. //==============================================================================
  1788. void Component::handleMessage (const Message& message)
  1789. {
  1790. if (message.intParameter1 == exitModalStateMessage)
  1791. {
  1792. exitModalState (message.intParameter2);
  1793. }
  1794. else if (message.intParameter1 == customCommandMessage)
  1795. {
  1796. handleCommandMessage (message.intParameter2);
  1797. }
  1798. }
  1799. //==============================================================================
  1800. void Component::postCommandMessage (const int commandId) throw()
  1801. {
  1802. postMessage (new Message (customCommandMessage, commandId, 0, 0));
  1803. }
  1804. void Component::handleCommandMessage (int)
  1805. {
  1806. // used by subclasses
  1807. }
  1808. //==============================================================================
  1809. void Component::addMouseListener (MouseListener* const newListener,
  1810. const bool wantsEventsForAllNestedChildComponents) throw()
  1811. {
  1812. // if component methods are being called from threads other than the message
  1813. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  1814. checkMessageManagerIsLocked
  1815. if (mouseListeners_ == 0)
  1816. mouseListeners_ = new VoidArray (4);
  1817. if (! mouseListeners_->contains (newListener))
  1818. {
  1819. if (wantsEventsForAllNestedChildComponents)
  1820. {
  1821. mouseListeners_->insert (0, newListener);
  1822. ++numDeepMouseListeners;
  1823. }
  1824. else
  1825. {
  1826. mouseListeners_->add (newListener);
  1827. }
  1828. }
  1829. }
  1830. void Component::removeMouseListener (MouseListener* const listenerToRemove) throw()
  1831. {
  1832. // if component methods are being called from threads other than the message
  1833. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  1834. checkMessageManagerIsLocked
  1835. if (mouseListeners_ != 0)
  1836. {
  1837. const int index = mouseListeners_->indexOf (listenerToRemove);
  1838. if (index >= 0)
  1839. {
  1840. if (index < numDeepMouseListeners)
  1841. --numDeepMouseListeners;
  1842. mouseListeners_->remove (index);
  1843. }
  1844. }
  1845. }
  1846. //==============================================================================
  1847. void Component::internalMouseEnter (int x, int y, int64 time)
  1848. {
  1849. if (isCurrentlyBlockedByAnotherModalComponent())
  1850. {
  1851. // if something else is modal, always just show a normal mouse cursor
  1852. if (componentUnderMouse == this)
  1853. {
  1854. ComponentPeer* const peer = getPeer();
  1855. if (peer != 0)
  1856. {
  1857. MouseCursor mc (MouseCursor::NormalCursor);
  1858. mc.showInWindow (peer);
  1859. }
  1860. }
  1861. return;
  1862. }
  1863. if (! flags.mouseInsideFlag)
  1864. {
  1865. flags.mouseInsideFlag = true;
  1866. flags.mouseOverFlag = true;
  1867. flags.draggingFlag = false;
  1868. if (isValidComponent())
  1869. {
  1870. const ComponentDeletionWatcher deletionChecker (this);
  1871. if (flags.repaintOnMouseActivityFlag)
  1872. repaint();
  1873. const MouseEvent me (x, y,
  1874. ModifierKeys::getCurrentModifiers(),
  1875. this,
  1876. Time (time),
  1877. x, y,
  1878. Time (time),
  1879. 0, false);
  1880. mouseEnter (me);
  1881. if (deletionChecker.hasBeenDeleted())
  1882. return;
  1883. Desktop::getInstance().resetTimer();
  1884. for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;)
  1885. {
  1886. ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseEnter (me);
  1887. if (deletionChecker.hasBeenDeleted())
  1888. return;
  1889. i = jmin (i, Desktop::getInstance().mouseListeners.size());
  1890. }
  1891. if (mouseListeners_ != 0)
  1892. {
  1893. for (int i = mouseListeners_->size(); --i >= 0;)
  1894. {
  1895. ((MouseListener*) mouseListeners_->getUnchecked(i))->mouseEnter (me);
  1896. if (deletionChecker.hasBeenDeleted())
  1897. return;
  1898. i = jmin (i, mouseListeners_->size());
  1899. }
  1900. }
  1901. const Component* p = parentComponent_;
  1902. while (p != 0)
  1903. {
  1904. const ComponentDeletionWatcher parentDeletionChecker (p);
  1905. for (int i = p->numDeepMouseListeners; --i >= 0;)
  1906. {
  1907. ((MouseListener*) (p->mouseListeners_->getUnchecked(i)))->mouseEnter (me);
  1908. if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted())
  1909. return;
  1910. i = jmin (i, p->numDeepMouseListeners);
  1911. }
  1912. p = p->parentComponent_;
  1913. }
  1914. }
  1915. }
  1916. if (componentUnderMouse == this)
  1917. internalUpdateMouseCursor (true);
  1918. }
  1919. void Component::internalMouseExit (int x, int y, int64 time)
  1920. {
  1921. const ComponentDeletionWatcher deletionChecker (this);
  1922. if (flags.draggingFlag)
  1923. {
  1924. internalMouseUp (ModifierKeys::getCurrentModifiers().getRawFlags(), x, y, time);
  1925. if (deletionChecker.hasBeenDeleted())
  1926. return;
  1927. }
  1928. enableUnboundedMouseMovement (false);
  1929. if (flags.mouseInsideFlag || flags.mouseOverFlag)
  1930. {
  1931. flags.mouseInsideFlag = false;
  1932. flags.mouseOverFlag = false;
  1933. flags.draggingFlag = false;
  1934. if (flags.repaintOnMouseActivityFlag)
  1935. repaint();
  1936. const MouseEvent me (x, y,
  1937. ModifierKeys::getCurrentModifiers(),
  1938. this,
  1939. Time (time),
  1940. x, y,
  1941. Time (time),
  1942. 0, false);
  1943. mouseExit (me);
  1944. if (deletionChecker.hasBeenDeleted())
  1945. return;
  1946. Desktop::getInstance().resetTimer();
  1947. for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;)
  1948. {
  1949. ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseExit (me);
  1950. if (deletionChecker.hasBeenDeleted())
  1951. return;
  1952. i = jmin (i, Desktop::getInstance().mouseListeners.size());
  1953. }
  1954. if (mouseListeners_ != 0)
  1955. {
  1956. for (int i = mouseListeners_->size(); --i >= 0;)
  1957. {
  1958. ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseExit (me);
  1959. if (deletionChecker.hasBeenDeleted())
  1960. return;
  1961. i = jmin (i, mouseListeners_->size());
  1962. }
  1963. }
  1964. const Component* p = parentComponent_;
  1965. while (p != 0)
  1966. {
  1967. const ComponentDeletionWatcher parentDeletionChecker (p);
  1968. for (int i = p->numDeepMouseListeners; --i >= 0;)
  1969. {
  1970. ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseExit (me);
  1971. if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted())
  1972. return;
  1973. i = jmin (i, p->numDeepMouseListeners);
  1974. }
  1975. p = p->parentComponent_;
  1976. }
  1977. }
  1978. }
  1979. //==============================================================================
  1980. class InternalDragRepeater : public Timer
  1981. {
  1982. public:
  1983. InternalDragRepeater()
  1984. {}
  1985. ~InternalDragRepeater()
  1986. {}
  1987. void timerCallback()
  1988. {
  1989. Component* const c = Component::getComponentUnderMouse();
  1990. if (c != 0 && c->isMouseButtonDown())
  1991. {
  1992. int x, y;
  1993. c->getMouseXYRelative (x, y);
  1994. // the offsets have been added on, so must be taken off before calling the
  1995. // drag.. otherwise they'll be added twice
  1996. x -= unboundedMouseOffsetX;
  1997. y -= unboundedMouseOffsetY;
  1998. c->internalMouseDrag (x, y, Time::currentTimeMillis());
  1999. }
  2000. }
  2001. juce_UseDebuggingNewOperator
  2002. };
  2003. static InternalDragRepeater* dragRepeater = 0;
  2004. void Component::beginDragAutoRepeat (const int interval)
  2005. {
  2006. if (interval > 0)
  2007. {
  2008. if (dragRepeater == 0)
  2009. dragRepeater = new InternalDragRepeater();
  2010. if (dragRepeater->getTimerInterval() != interval)
  2011. dragRepeater->startTimer (interval);
  2012. }
  2013. else
  2014. {
  2015. deleteAndZero (dragRepeater);
  2016. }
  2017. }
  2018. //==============================================================================
  2019. void Component::internalMouseDown (const int x, const int y)
  2020. {
  2021. const ComponentDeletionWatcher deletionChecker (this);
  2022. if (isCurrentlyBlockedByAnotherModalComponent())
  2023. {
  2024. internalModalInputAttempt();
  2025. if (deletionChecker.hasBeenDeleted())
  2026. return;
  2027. // If processing the input attempt has exited the modal loop, we'll allow the event
  2028. // to be delivered..
  2029. if (isCurrentlyBlockedByAnotherModalComponent())
  2030. {
  2031. // allow blocked mouse-events to go to global listeners..
  2032. const MouseEvent me (x, y,
  2033. ModifierKeys::getCurrentModifiers(),
  2034. this,
  2035. Time (juce_recentMouseDownTimes[0]),
  2036. x, y,
  2037. Time (juce_recentMouseDownTimes[0]),
  2038. countMouseClicks(),
  2039. false);
  2040. Desktop::getInstance().resetTimer();
  2041. for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;)
  2042. {
  2043. ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseDown (me);
  2044. if (deletionChecker.hasBeenDeleted())
  2045. return;
  2046. i = jmin (i, Desktop::getInstance().mouseListeners.size());
  2047. }
  2048. return;
  2049. }
  2050. }
  2051. {
  2052. Component* c = this;
  2053. while (c != 0)
  2054. {
  2055. if (c->isBroughtToFrontOnMouseClick())
  2056. {
  2057. c->toFront (true);
  2058. if (deletionChecker.hasBeenDeleted())
  2059. return;
  2060. }
  2061. c = c->parentComponent_;
  2062. }
  2063. }
  2064. if (! flags.dontFocusOnMouseClickFlag)
  2065. grabFocusInternal (focusChangedByMouseClick);
  2066. if (! deletionChecker.hasBeenDeleted())
  2067. {
  2068. flags.draggingFlag = true;
  2069. flags.mouseOverFlag = true;
  2070. if (flags.repaintOnMouseActivityFlag)
  2071. repaint();
  2072. const MouseEvent me (x, y,
  2073. ModifierKeys::getCurrentModifiers(),
  2074. this,
  2075. Time (juce_recentMouseDownTimes[0]),
  2076. x, y,
  2077. Time (juce_recentMouseDownTimes[0]),
  2078. countMouseClicks(),
  2079. false);
  2080. mouseDown (me);
  2081. if (deletionChecker.hasBeenDeleted())
  2082. return;
  2083. Desktop::getInstance().resetTimer();
  2084. for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;)
  2085. {
  2086. ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseDown (me);
  2087. if (deletionChecker.hasBeenDeleted())
  2088. return;
  2089. i = jmin (i, Desktop::getInstance().mouseListeners.size());
  2090. }
  2091. if (mouseListeners_ != 0)
  2092. {
  2093. for (int i = mouseListeners_->size(); --i >= 0;)
  2094. {
  2095. ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseDown (me);
  2096. if (deletionChecker.hasBeenDeleted())
  2097. return;
  2098. i = jmin (i, mouseListeners_->size());
  2099. }
  2100. }
  2101. const Component* p = parentComponent_;
  2102. while (p != 0)
  2103. {
  2104. const ComponentDeletionWatcher parentDeletionChecker (p);
  2105. for (int i = p->numDeepMouseListeners; --i >= 0;)
  2106. {
  2107. ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseDown (me);
  2108. if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted())
  2109. return;
  2110. i = jmin (i, p->numDeepMouseListeners);
  2111. }
  2112. p = p->parentComponent_;
  2113. }
  2114. }
  2115. }
  2116. //==============================================================================
  2117. void Component::internalMouseUp (const int oldModifiers, int x, int y, const int64 time)
  2118. {
  2119. if (isValidComponent() && flags.draggingFlag)
  2120. {
  2121. flags.draggingFlag = false;
  2122. deleteAndZero (dragRepeater);
  2123. x += unboundedMouseOffsetX;
  2124. y += unboundedMouseOffsetY;
  2125. juce_LastMousePosX = x;
  2126. juce_LastMousePosY = y;
  2127. relativePositionToGlobal (juce_LastMousePosX, juce_LastMousePosY);
  2128. const ComponentDeletionWatcher deletionChecker (this);
  2129. if (flags.repaintOnMouseActivityFlag)
  2130. repaint();
  2131. int mdx = juce_recentMouseDownX[0];
  2132. int mdy = juce_recentMouseDownY[0];
  2133. globalPositionToRelative (mdx, mdy);
  2134. const MouseEvent me (x, y,
  2135. oldModifiers,
  2136. this,
  2137. Time (time),
  2138. mdx, mdy,
  2139. Time (juce_recentMouseDownTimes [0]),
  2140. countMouseClicks(),
  2141. juce_MouseHasMovedSignificantlySincePressed
  2142. || juce_recentMouseDownTimes[0] + 300 < time);
  2143. mouseUp (me);
  2144. if (deletionChecker.hasBeenDeleted())
  2145. return;
  2146. Desktop::getInstance().resetTimer();
  2147. for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;)
  2148. {
  2149. ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseUp (me);
  2150. if (deletionChecker.hasBeenDeleted())
  2151. return;
  2152. i = jmin (i, Desktop::getInstance().mouseListeners.size());
  2153. }
  2154. if (mouseListeners_ != 0)
  2155. {
  2156. for (int i = mouseListeners_->size(); --i >= 0;)
  2157. {
  2158. ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseUp (me);
  2159. if (deletionChecker.hasBeenDeleted())
  2160. return;
  2161. i = jmin (i, mouseListeners_->size());
  2162. }
  2163. }
  2164. {
  2165. const Component* p = parentComponent_;
  2166. while (p != 0)
  2167. {
  2168. const ComponentDeletionWatcher parentDeletionChecker (p);
  2169. for (int i = p->numDeepMouseListeners; --i >= 0;)
  2170. {
  2171. ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseUp (me);
  2172. if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted())
  2173. return;
  2174. i = jmin (i, p->numDeepMouseListeners);
  2175. }
  2176. p = p->parentComponent_;
  2177. }
  2178. }
  2179. // check for double-click
  2180. if (me.getNumberOfClicks() >= 2)
  2181. {
  2182. const int numListeners = (mouseListeners_ != 0) ? mouseListeners_->size() : 0;
  2183. mouseDoubleClick (me);
  2184. int i;
  2185. for (i = Desktop::getInstance().mouseListeners.size(); --i >= 0;)
  2186. {
  2187. ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseDoubleClick (me);
  2188. if (deletionChecker.hasBeenDeleted())
  2189. return;
  2190. i = jmin (i, Desktop::getInstance().mouseListeners.size());
  2191. }
  2192. for (i = numListeners; --i >= 0;)
  2193. {
  2194. if (deletionChecker.hasBeenDeleted() || mouseListeners_ == 0)
  2195. return;
  2196. MouseListener* const ml = (MouseListener*)((*mouseListeners_)[i]);
  2197. if (ml != 0)
  2198. ml->mouseDoubleClick (me);
  2199. }
  2200. if (deletionChecker.hasBeenDeleted())
  2201. return;
  2202. const Component* p = parentComponent_;
  2203. while (p != 0)
  2204. {
  2205. const ComponentDeletionWatcher parentDeletionChecker (p);
  2206. for (i = p->numDeepMouseListeners; --i >= 0;)
  2207. {
  2208. ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseDoubleClick (me);
  2209. if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted())
  2210. return;
  2211. i = jmin (i, p->numDeepMouseListeners);
  2212. }
  2213. p = p->parentComponent_;
  2214. }
  2215. }
  2216. }
  2217. enableUnboundedMouseMovement (false);
  2218. }
  2219. void Component::internalMouseDrag (int x, int y, const int64 time)
  2220. {
  2221. if (isValidComponent() && flags.draggingFlag)
  2222. {
  2223. flags.mouseOverFlag = reallyContains (x, y, false);
  2224. x += unboundedMouseOffsetX;
  2225. y += unboundedMouseOffsetY;
  2226. juce_LastMousePosX = x;
  2227. juce_LastMousePosY = y;
  2228. relativePositionToGlobal (juce_LastMousePosX, juce_LastMousePosY);
  2229. juce_MouseHasMovedSignificantlySincePressed
  2230. = juce_MouseHasMovedSignificantlySincePressed
  2231. || abs (juce_recentMouseDownX[0] - juce_LastMousePosX) >= 4
  2232. || abs (juce_recentMouseDownY[0] - juce_LastMousePosY) >= 4;
  2233. const ComponentDeletionWatcher deletionChecker (this);
  2234. int mdx = juce_recentMouseDownX[0];
  2235. int mdy = juce_recentMouseDownY[0];
  2236. globalPositionToRelative (mdx, mdy);
  2237. const MouseEvent me (x, y,
  2238. ModifierKeys::getCurrentModifiers(),
  2239. this,
  2240. Time (time),
  2241. mdx, mdy,
  2242. Time (juce_recentMouseDownTimes[0]),
  2243. countMouseClicks(),
  2244. juce_MouseHasMovedSignificantlySincePressed
  2245. || juce_recentMouseDownTimes[0] + 300 < time);
  2246. mouseDrag (me);
  2247. if (deletionChecker.hasBeenDeleted())
  2248. return;
  2249. Desktop::getInstance().resetTimer();
  2250. for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;)
  2251. {
  2252. ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseDrag (me);
  2253. if (deletionChecker.hasBeenDeleted())
  2254. return;
  2255. i = jmin (i, Desktop::getInstance().mouseListeners.size());
  2256. }
  2257. if (mouseListeners_ != 0)
  2258. {
  2259. for (int i = mouseListeners_->size(); --i >= 0;)
  2260. {
  2261. ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseDrag (me);
  2262. if (deletionChecker.hasBeenDeleted())
  2263. return;
  2264. i = jmin (i, mouseListeners_->size());
  2265. }
  2266. }
  2267. const Component* p = parentComponent_;
  2268. while (p != 0)
  2269. {
  2270. const ComponentDeletionWatcher parentDeletionChecker (p);
  2271. for (int i = p->numDeepMouseListeners; --i >= 0;)
  2272. {
  2273. ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseDrag (me);
  2274. if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted())
  2275. return;
  2276. i = jmin (i, p->numDeepMouseListeners);
  2277. }
  2278. p = p->parentComponent_;
  2279. }
  2280. if (this == componentUnderMouse)
  2281. {
  2282. if (isUnboundedMouseModeOn)
  2283. {
  2284. Rectangle screenArea (getParentMonitorArea().expanded (-2, -2));
  2285. int mx, my;
  2286. Desktop::getMousePosition (mx, my);
  2287. if (! screenArea.contains (mx, my))
  2288. {
  2289. int deltaX = 0, deltaY = 0;
  2290. if (mx <= screenArea.getX() || mx >= screenArea.getRight())
  2291. deltaX = getScreenX() + getWidth() / 2 - mx;
  2292. if (my <= screenArea.getY() || my >= screenArea.getBottom())
  2293. deltaY = getScreenY() + getHeight() / 2 - my;
  2294. unboundedMouseOffsetX -= deltaX;
  2295. unboundedMouseOffsetY -= deltaY;
  2296. Desktop::setMousePosition (mx + deltaX,
  2297. my + deltaY);
  2298. }
  2299. else if (isCursorVisibleUntilOffscreen
  2300. && (unboundedMouseOffsetX != 0 || unboundedMouseOffsetY != 0)
  2301. && screenArea.contains (mx + unboundedMouseOffsetX,
  2302. my + unboundedMouseOffsetY))
  2303. {
  2304. mx += unboundedMouseOffsetX;
  2305. my += unboundedMouseOffsetY;
  2306. unboundedMouseOffsetX = 0;
  2307. unboundedMouseOffsetY = 0;
  2308. Desktop::setMousePosition (mx, my);
  2309. }
  2310. }
  2311. internalUpdateMouseCursor (false);
  2312. }
  2313. }
  2314. }
  2315. void Component::internalMouseMove (const int x, const int y, const int64 time)
  2316. {
  2317. const ComponentDeletionWatcher deletionChecker (this);
  2318. if (isValidComponent())
  2319. {
  2320. const MouseEvent me (x, y,
  2321. ModifierKeys::getCurrentModifiers(),
  2322. this,
  2323. Time (time),
  2324. x, y,
  2325. Time (time),
  2326. 0, false);
  2327. if (isCurrentlyBlockedByAnotherModalComponent())
  2328. {
  2329. // allow blocked mouse-events to go to global listeners..
  2330. Desktop::getInstance().sendMouseMove();
  2331. }
  2332. else
  2333. {
  2334. if (this == componentUnderMouse)
  2335. internalUpdateMouseCursor (false);
  2336. flags.mouseOverFlag = true;
  2337. mouseMove (me);
  2338. if (deletionChecker.hasBeenDeleted())
  2339. return;
  2340. Desktop::getInstance().resetTimer();
  2341. for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;)
  2342. {
  2343. ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseMove (me);
  2344. if (deletionChecker.hasBeenDeleted())
  2345. return;
  2346. i = jmin (i, Desktop::getInstance().mouseListeners.size());
  2347. }
  2348. if (mouseListeners_ != 0)
  2349. {
  2350. for (int i = mouseListeners_->size(); --i >= 0;)
  2351. {
  2352. ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseMove (me);
  2353. if (deletionChecker.hasBeenDeleted())
  2354. return;
  2355. i = jmin (i, mouseListeners_->size());
  2356. }
  2357. }
  2358. const Component* p = parentComponent_;
  2359. while (p != 0)
  2360. {
  2361. const ComponentDeletionWatcher parentDeletionChecker (p);
  2362. for (int i = p->numDeepMouseListeners; --i >= 0;)
  2363. {
  2364. ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseMove (me);
  2365. if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted())
  2366. return;
  2367. i = jmin (i, p->numDeepMouseListeners);
  2368. }
  2369. p = p->parentComponent_;
  2370. }
  2371. }
  2372. }
  2373. }
  2374. void Component::internalMouseWheel (const int intAmountX, const int intAmountY, const int64 time)
  2375. {
  2376. const ComponentDeletionWatcher deletionChecker (this);
  2377. const float wheelIncrementX = intAmountX * (1.0f / 256.0f);
  2378. const float wheelIncrementY = intAmountY * (1.0f / 256.0f);
  2379. int mx, my;
  2380. getMouseXYRelative (mx, my);
  2381. const MouseEvent me (mx, my,
  2382. ModifierKeys::getCurrentModifiers(),
  2383. this,
  2384. Time (time),
  2385. mx, my,
  2386. Time (time),
  2387. 0, false);
  2388. if (isCurrentlyBlockedByAnotherModalComponent())
  2389. {
  2390. // allow blocked mouse-events to go to global listeners..
  2391. for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;)
  2392. {
  2393. ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseWheelMove (me, wheelIncrementX, wheelIncrementY);
  2394. if (deletionChecker.hasBeenDeleted())
  2395. return;
  2396. i = jmin (i, Desktop::getInstance().mouseListeners.size());
  2397. }
  2398. }
  2399. else
  2400. {
  2401. mouseWheelMove (me, wheelIncrementX, wheelIncrementY);
  2402. if (deletionChecker.hasBeenDeleted())
  2403. return;
  2404. for (int i = Desktop::getInstance().mouseListeners.size(); --i >= 0;)
  2405. {
  2406. ((MouseListener*) Desktop::getInstance().mouseListeners[i])->mouseWheelMove (me, wheelIncrementX, wheelIncrementY);
  2407. if (deletionChecker.hasBeenDeleted())
  2408. return;
  2409. i = jmin (i, Desktop::getInstance().mouseListeners.size());
  2410. }
  2411. if (mouseListeners_ != 0)
  2412. {
  2413. for (int i = mouseListeners_->size(); --i >= 0;)
  2414. {
  2415. ((MouseListener*) mouseListeners_->getUnchecked (i))->mouseWheelMove (me, wheelIncrementX, wheelIncrementY);
  2416. if (deletionChecker.hasBeenDeleted())
  2417. return;
  2418. i = jmin (i, mouseListeners_->size());
  2419. }
  2420. }
  2421. const Component* p = parentComponent_;
  2422. while (p != 0)
  2423. {
  2424. const ComponentDeletionWatcher parentDeletionChecker (p);
  2425. for (int i = p->numDeepMouseListeners; --i >= 0;)
  2426. {
  2427. ((MouseListener*) (p->mouseListeners_->getUnchecked (i)))->mouseWheelMove (me, wheelIncrementX, wheelIncrementY);
  2428. if (deletionChecker.hasBeenDeleted() || parentDeletionChecker.hasBeenDeleted())
  2429. return;
  2430. i = jmin (i, p->numDeepMouseListeners);
  2431. }
  2432. p = p->parentComponent_;
  2433. }
  2434. sendFakeMouseMove();
  2435. }
  2436. }
  2437. void Component::sendFakeMouseMove() const
  2438. {
  2439. ComponentPeer* const peer = getPeer();
  2440. if (peer != 0)
  2441. peer->sendFakeMouseMove();
  2442. }
  2443. void Component::broughtToFront()
  2444. {
  2445. }
  2446. void Component::internalBroughtToFront()
  2447. {
  2448. if (isValidComponent())
  2449. {
  2450. if (flags.hasHeavyweightPeerFlag)
  2451. Desktop::getInstance().componentBroughtToFront (this);
  2452. const ComponentDeletionWatcher deletionChecker (this);
  2453. broughtToFront();
  2454. if (deletionChecker.hasBeenDeleted())
  2455. return;
  2456. if (componentListeners_ != 0)
  2457. {
  2458. for (int i = componentListeners_->size(); --i >= 0;)
  2459. {
  2460. ((ComponentListener*) componentListeners_->getUnchecked (i))
  2461. ->componentBroughtToFront (*this);
  2462. if (deletionChecker.hasBeenDeleted())
  2463. return;
  2464. i = jmin (i, componentListeners_->size());
  2465. }
  2466. }
  2467. // when brought to the front and there's a modal component blocking this one,
  2468. // we need to bring the modal one to the front instead..
  2469. Component* const cm = getCurrentlyModalComponent();
  2470. if (cm != 0 && cm->getTopLevelComponent() != getTopLevelComponent())
  2471. bringModalComponentToFront();
  2472. }
  2473. }
  2474. void Component::focusGained (FocusChangeType)
  2475. {
  2476. // base class does nothing
  2477. }
  2478. void Component::internalFocusGain (const FocusChangeType cause)
  2479. {
  2480. const ComponentDeletionWatcher deletionChecker (this);
  2481. focusGained (cause);
  2482. if (! deletionChecker.hasBeenDeleted())
  2483. internalChildFocusChange (cause);
  2484. }
  2485. void Component::focusLost (FocusChangeType)
  2486. {
  2487. // base class does nothing
  2488. }
  2489. void Component::internalFocusLoss (const FocusChangeType cause)
  2490. {
  2491. const ComponentDeletionWatcher deletionChecker (this);
  2492. focusLost (focusChangedDirectly);
  2493. if (! deletionChecker.hasBeenDeleted())
  2494. internalChildFocusChange (cause);
  2495. }
  2496. void Component::focusOfChildComponentChanged (FocusChangeType /*cause*/)
  2497. {
  2498. // base class does nothing
  2499. }
  2500. void Component::internalChildFocusChange (FocusChangeType cause)
  2501. {
  2502. const bool childIsNowFocused = hasKeyboardFocus (true);
  2503. if (flags.childCompFocusedFlag != childIsNowFocused)
  2504. {
  2505. flags.childCompFocusedFlag = childIsNowFocused;
  2506. const ComponentDeletionWatcher deletionChecker (this);
  2507. focusOfChildComponentChanged (cause);
  2508. if (deletionChecker.hasBeenDeleted())
  2509. return;
  2510. }
  2511. if (parentComponent_ != 0)
  2512. parentComponent_->internalChildFocusChange (cause);
  2513. }
  2514. //==============================================================================
  2515. bool Component::isEnabled() const throw()
  2516. {
  2517. return (! flags.isDisabledFlag)
  2518. && (parentComponent_ == 0 || parentComponent_->isEnabled());
  2519. }
  2520. void Component::setEnabled (const bool shouldBeEnabled)
  2521. {
  2522. if (flags.isDisabledFlag == shouldBeEnabled)
  2523. {
  2524. flags.isDisabledFlag = ! shouldBeEnabled;
  2525. // if any parent components are disabled, setting our flag won't make a difference,
  2526. // so no need to send a change message
  2527. if (parentComponent_ == 0 || parentComponent_->isEnabled())
  2528. sendEnablementChangeMessage();
  2529. }
  2530. }
  2531. void Component::sendEnablementChangeMessage()
  2532. {
  2533. const ComponentDeletionWatcher deletionChecker (this);
  2534. enablementChanged();
  2535. if (deletionChecker.hasBeenDeleted())
  2536. return;
  2537. for (int i = getNumChildComponents(); --i >= 0;)
  2538. {
  2539. Component* const c = getChildComponent (i);
  2540. if (c != 0)
  2541. {
  2542. c->sendEnablementChangeMessage();
  2543. if (deletionChecker.hasBeenDeleted())
  2544. return;
  2545. }
  2546. }
  2547. }
  2548. void Component::enablementChanged()
  2549. {
  2550. }
  2551. //==============================================================================
  2552. void Component::setWantsKeyboardFocus (const bool wantsFocus) throw()
  2553. {
  2554. flags.wantsFocusFlag = wantsFocus;
  2555. }
  2556. void Component::setMouseClickGrabsKeyboardFocus (const bool shouldGrabFocus)
  2557. {
  2558. flags.dontFocusOnMouseClickFlag = ! shouldGrabFocus;
  2559. }
  2560. bool Component::getMouseClickGrabsKeyboardFocus() const throw()
  2561. {
  2562. return ! flags.dontFocusOnMouseClickFlag;
  2563. }
  2564. bool Component::getWantsKeyboardFocus() const throw()
  2565. {
  2566. return flags.wantsFocusFlag && ! flags.isDisabledFlag;
  2567. }
  2568. void Component::setFocusContainer (const bool isFocusContainer) throw()
  2569. {
  2570. flags.isFocusContainerFlag = isFocusContainer;
  2571. }
  2572. bool Component::isFocusContainer() const throw()
  2573. {
  2574. return flags.isFocusContainerFlag;
  2575. }
  2576. int Component::getExplicitFocusOrder() const throw()
  2577. {
  2578. return getComponentPropertyInt (T("_jexfo"), false, 0);
  2579. }
  2580. void Component::setExplicitFocusOrder (const int newFocusOrderIndex) throw()
  2581. {
  2582. setComponentProperty (T("_jexfo"), newFocusOrderIndex);
  2583. }
  2584. KeyboardFocusTraverser* Component::createFocusTraverser()
  2585. {
  2586. if (flags.isFocusContainerFlag || parentComponent_ == 0)
  2587. return new KeyboardFocusTraverser();
  2588. return parentComponent_->createFocusTraverser();
  2589. }
  2590. void Component::takeKeyboardFocus (const FocusChangeType cause)
  2591. {
  2592. // give the focus to this component
  2593. if (currentlyFocusedComponent != this)
  2594. {
  2595. JUCE_TRY
  2596. {
  2597. // get the focus onto our desktop window
  2598. ComponentPeer* const peer = getPeer();
  2599. if (peer != 0)
  2600. {
  2601. const ComponentDeletionWatcher deletionChecker (this);
  2602. peer->grabFocus();
  2603. if (peer->isFocused() && currentlyFocusedComponent != this)
  2604. {
  2605. Component* const componentLosingFocus = currentlyFocusedComponent;
  2606. currentlyFocusedComponent = this;
  2607. Desktop::getInstance().triggerFocusCallback();
  2608. // call this after setting currentlyFocusedComponent so that the one that's
  2609. // losing it has a chance to see where focus is going
  2610. if (componentLosingFocus->isValidComponent())
  2611. componentLosingFocus->internalFocusLoss (cause);
  2612. if (currentlyFocusedComponent == this)
  2613. {
  2614. focusGained (cause);
  2615. if (! deletionChecker.hasBeenDeleted())
  2616. internalChildFocusChange (cause);
  2617. }
  2618. }
  2619. }
  2620. }
  2621. #if JUCE_CATCH_UNHANDLED_EXCEPTIONS
  2622. catch (const std::exception& e)
  2623. {
  2624. currentlyFocusedComponent = 0;
  2625. Desktop::getInstance().triggerFocusCallback();
  2626. JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__);
  2627. }
  2628. catch (...)
  2629. {
  2630. currentlyFocusedComponent = 0;
  2631. Desktop::getInstance().triggerFocusCallback();
  2632. JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__);
  2633. }
  2634. #endif
  2635. }
  2636. }
  2637. void Component::grabFocusInternal (const FocusChangeType cause, const bool canTryParent)
  2638. {
  2639. if (isShowing())
  2640. {
  2641. if (flags.wantsFocusFlag && (isEnabled() || parentComponent_ == 0))
  2642. {
  2643. takeKeyboardFocus (cause);
  2644. }
  2645. else
  2646. {
  2647. if (isParentOf (currentlyFocusedComponent)
  2648. && currentlyFocusedComponent->isShowing())
  2649. {
  2650. // do nothing if the focused component is actually a child of ours..
  2651. }
  2652. else
  2653. {
  2654. // find the default child component..
  2655. KeyboardFocusTraverser* const traverser = createFocusTraverser();
  2656. if (traverser != 0)
  2657. {
  2658. Component* const defaultComp = traverser->getDefaultComponent (this);
  2659. delete traverser;
  2660. if (defaultComp != 0)
  2661. {
  2662. defaultComp->grabFocusInternal (cause, false);
  2663. return;
  2664. }
  2665. }
  2666. if (canTryParent && parentComponent_ != 0)
  2667. {
  2668. // if no children want it and we're allowed to try our parent comp,
  2669. // then pass up to parent, which will try our siblings.
  2670. parentComponent_->grabFocusInternal (cause, true);
  2671. }
  2672. }
  2673. }
  2674. }
  2675. }
  2676. void Component::grabKeyboardFocus()
  2677. {
  2678. // if component methods are being called from threads other than the message
  2679. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  2680. checkMessageManagerIsLocked
  2681. grabFocusInternal (focusChangedDirectly);
  2682. }
  2683. void Component::moveKeyboardFocusToSibling (const bool moveToNext)
  2684. {
  2685. // if component methods are being called from threads other than the message
  2686. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
  2687. checkMessageManagerIsLocked
  2688. if (parentComponent_ != 0)
  2689. {
  2690. KeyboardFocusTraverser* const traverser = createFocusTraverser();
  2691. if (traverser != 0)
  2692. {
  2693. Component* const nextComp = moveToNext ? traverser->getNextComponent (this)
  2694. : traverser->getPreviousComponent (this);
  2695. delete traverser;
  2696. if (nextComp != 0)
  2697. {
  2698. if (nextComp->isCurrentlyBlockedByAnotherModalComponent())
  2699. {
  2700. const ComponentDeletionWatcher deletionChecker (nextComp);
  2701. internalModalInputAttempt();
  2702. if (deletionChecker.hasBeenDeleted()
  2703. || nextComp->isCurrentlyBlockedByAnotherModalComponent())
  2704. return;
  2705. }
  2706. nextComp->grabFocusInternal (focusChangedByTabKey);
  2707. return;
  2708. }
  2709. }
  2710. parentComponent_->moveKeyboardFocusToSibling (moveToNext);
  2711. }
  2712. }
  2713. bool Component::hasKeyboardFocus (const bool trueIfChildIsFocused) const throw()
  2714. {
  2715. return (currentlyFocusedComponent == this)
  2716. || (trueIfChildIsFocused && isParentOf (currentlyFocusedComponent));
  2717. }
  2718. Component* JUCE_CALLTYPE Component::getCurrentlyFocusedComponent() throw()
  2719. {
  2720. return currentlyFocusedComponent;
  2721. }
  2722. void Component::giveAwayFocus()
  2723. {
  2724. // use a copy so we can clear the value before the call
  2725. Component* const componentLosingFocus = currentlyFocusedComponent;
  2726. currentlyFocusedComponent = 0;
  2727. Desktop::getInstance().triggerFocusCallback();
  2728. if (componentLosingFocus->isValidComponent())
  2729. componentLosingFocus->internalFocusLoss (focusChangedDirectly);
  2730. }
  2731. //==============================================================================
  2732. bool Component::isMouseOver() const throw()
  2733. {
  2734. return flags.mouseOverFlag;
  2735. }
  2736. bool Component::isMouseButtonDown() const throw()
  2737. {
  2738. return flags.draggingFlag;
  2739. }
  2740. bool Component::isMouseOverOrDragging() const throw()
  2741. {
  2742. return flags.mouseOverFlag || flags.draggingFlag;
  2743. }
  2744. bool JUCE_CALLTYPE Component::isMouseButtonDownAnywhere() throw()
  2745. {
  2746. return ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown();
  2747. }
  2748. void Component::getMouseXYRelative (int& mx, int& my) const throw()
  2749. {
  2750. Desktop::getMousePosition (mx, my);
  2751. globalPositionToRelative (mx, my);
  2752. mx += unboundedMouseOffsetX;
  2753. my += unboundedMouseOffsetY;
  2754. }
  2755. void Component::enableUnboundedMouseMovement (bool enable,
  2756. bool keepCursorVisibleUntilOffscreen) throw()
  2757. {
  2758. enable = enable && isMouseButtonDown();
  2759. isCursorVisibleUntilOffscreen = keepCursorVisibleUntilOffscreen;
  2760. if (enable != isUnboundedMouseModeOn)
  2761. {
  2762. if ((! enable) && ((! isCursorVisibleUntilOffscreen)
  2763. || unboundedMouseOffsetX != 0
  2764. || unboundedMouseOffsetY != 0))
  2765. {
  2766. // when released, return the mouse to within the component's bounds
  2767. int mx, my;
  2768. getMouseXYRelative (mx, my);
  2769. mx = jlimit (0, getWidth(), mx);
  2770. my = jlimit (0, getHeight(), my);
  2771. relativePositionToGlobal (mx, my);
  2772. Desktop::setMousePosition (mx, my);
  2773. }
  2774. isUnboundedMouseModeOn = enable;
  2775. unboundedMouseOffsetX = 0;
  2776. unboundedMouseOffsetY = 0;
  2777. internalUpdateMouseCursor (true);
  2778. }
  2779. }
  2780. Component* JUCE_CALLTYPE Component::getComponentUnderMouse() throw()
  2781. {
  2782. return componentUnderMouse;
  2783. }
  2784. //==============================================================================
  2785. const Rectangle Component::getParentMonitorArea() const throw()
  2786. {
  2787. int centreX = getWidth() / 2;
  2788. int centreY = getHeight() / 2;
  2789. relativePositionToGlobal (centreX, centreY);
  2790. return Desktop::getInstance().getMonitorAreaContaining (centreX, centreY);
  2791. }
  2792. //==============================================================================
  2793. void Component::addKeyListener (KeyListener* const newListener) throw()
  2794. {
  2795. if (keyListeners_ == 0)
  2796. keyListeners_ = new VoidArray (4);
  2797. keyListeners_->addIfNotAlreadyThere (newListener);
  2798. }
  2799. void Component::removeKeyListener (KeyListener* const listenerToRemove) throw()
  2800. {
  2801. if (keyListeners_ != 0)
  2802. keyListeners_->removeValue (listenerToRemove);
  2803. }
  2804. bool Component::keyPressed (const KeyPress&)
  2805. {
  2806. return false;
  2807. }
  2808. bool Component::keyStateChanged (const bool /*isKeyDown*/)
  2809. {
  2810. return false;
  2811. }
  2812. void Component::modifierKeysChanged (const ModifierKeys& modifiers)
  2813. {
  2814. if (parentComponent_ != 0)
  2815. parentComponent_->modifierKeysChanged (modifiers);
  2816. }
  2817. void Component::internalModifierKeysChanged()
  2818. {
  2819. sendFakeMouseMove();
  2820. modifierKeysChanged (ModifierKeys::getCurrentModifiers());
  2821. }
  2822. //==============================================================================
  2823. ComponentPeer* Component::getPeer() const throw()
  2824. {
  2825. if (flags.hasHeavyweightPeerFlag)
  2826. return ComponentPeer::getPeerFor (this);
  2827. else if (parentComponent_ != 0)
  2828. return parentComponent_->getPeer();
  2829. else
  2830. return 0;
  2831. }
  2832. //==============================================================================
  2833. const String Component::getComponentProperty (const String& keyName,
  2834. const bool useParentComponentIfNotFound,
  2835. const String& defaultReturnValue) const throw()
  2836. {
  2837. if (propertySet_ != 0 && ((! useParentComponentIfNotFound) || propertySet_->containsKey (keyName)))
  2838. return propertySet_->getValue (keyName, defaultReturnValue);
  2839. if (useParentComponentIfNotFound && (parentComponent_ != 0))
  2840. return parentComponent_->getComponentProperty (keyName, true, defaultReturnValue);
  2841. return defaultReturnValue;
  2842. }
  2843. int Component::getComponentPropertyInt (const String& keyName,
  2844. const bool useParentComponentIfNotFound,
  2845. const int defaultReturnValue) const throw()
  2846. {
  2847. if (propertySet_ != 0 && ((! useParentComponentIfNotFound) || propertySet_->containsKey (keyName)))
  2848. return propertySet_->getIntValue (keyName, defaultReturnValue);
  2849. if (useParentComponentIfNotFound && (parentComponent_ != 0))
  2850. return parentComponent_->getComponentPropertyInt (keyName, true, defaultReturnValue);
  2851. return defaultReturnValue;
  2852. }
  2853. double Component::getComponentPropertyDouble (const String& keyName,
  2854. const bool useParentComponentIfNotFound,
  2855. const double defaultReturnValue) const throw()
  2856. {
  2857. if (propertySet_ != 0 && ((! useParentComponentIfNotFound) || propertySet_->containsKey (keyName)))
  2858. return propertySet_->getDoubleValue (keyName, defaultReturnValue);
  2859. if (useParentComponentIfNotFound && (parentComponent_ != 0))
  2860. return parentComponent_->getComponentPropertyDouble (keyName, true, defaultReturnValue);
  2861. return defaultReturnValue;
  2862. }
  2863. bool Component::getComponentPropertyBool (const String& keyName,
  2864. const bool useParentComponentIfNotFound,
  2865. const bool defaultReturnValue) const throw()
  2866. {
  2867. if (propertySet_ != 0 && ((! useParentComponentIfNotFound) || propertySet_->containsKey (keyName)))
  2868. return propertySet_->getBoolValue (keyName, defaultReturnValue);
  2869. if (useParentComponentIfNotFound && (parentComponent_ != 0))
  2870. return parentComponent_->getComponentPropertyBool (keyName, true, defaultReturnValue);
  2871. return defaultReturnValue;
  2872. }
  2873. const Colour Component::getComponentPropertyColour (const String& keyName,
  2874. const bool useParentComponentIfNotFound,
  2875. const Colour& defaultReturnValue) const throw()
  2876. {
  2877. return Colour ((uint32) getComponentPropertyInt (keyName,
  2878. useParentComponentIfNotFound,
  2879. defaultReturnValue.getARGB()));
  2880. }
  2881. void Component::setComponentProperty (const String& keyName, const String& value) throw()
  2882. {
  2883. if (propertySet_ == 0)
  2884. propertySet_ = new PropertySet();
  2885. propertySet_->setValue (keyName, value);
  2886. }
  2887. void Component::setComponentProperty (const String& keyName, const int value) throw()
  2888. {
  2889. if (propertySet_ == 0)
  2890. propertySet_ = new PropertySet();
  2891. propertySet_->setValue (keyName, value);
  2892. }
  2893. void Component::setComponentProperty (const String& keyName, const double value) throw()
  2894. {
  2895. if (propertySet_ == 0)
  2896. propertySet_ = new PropertySet();
  2897. propertySet_->setValue (keyName, value);
  2898. }
  2899. void Component::setComponentProperty (const String& keyName, const bool value) throw()
  2900. {
  2901. if (propertySet_ == 0)
  2902. propertySet_ = new PropertySet();
  2903. propertySet_->setValue (keyName, value);
  2904. }
  2905. void Component::setComponentProperty (const String& keyName, const Colour& colour) throw()
  2906. {
  2907. setComponentProperty (keyName, (int) colour.getARGB());
  2908. }
  2909. void Component::removeComponentProperty (const String& keyName) throw()
  2910. {
  2911. if (propertySet_ != 0)
  2912. propertySet_->removeValue (keyName);
  2913. }
  2914. //==============================================================================
  2915. ComponentDeletionWatcher::ComponentDeletionWatcher (const Component* const componentToWatch_) throw()
  2916. : componentToWatch (componentToWatch_),
  2917. componentUID (componentToWatch_->getComponentUID())
  2918. {
  2919. // not possible to check on an already-deleted object..
  2920. jassert (componentToWatch_->isValidComponent());
  2921. }
  2922. ComponentDeletionWatcher::~ComponentDeletionWatcher() throw() {}
  2923. bool ComponentDeletionWatcher::hasBeenDeleted() const throw()
  2924. {
  2925. return ! (componentToWatch->isValidComponent()
  2926. && componentToWatch->getComponentUID() == componentUID);
  2927. }
  2928. const Component* ComponentDeletionWatcher::getComponent() const throw()
  2929. {
  2930. return hasBeenDeleted() ? 0 : componentToWatch;
  2931. }
  2932. END_JUCE_NAMESPACE