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.

221 lines
6.0KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. class DropShadower::ShadowWindow : public Component
  21. {
  22. public:
  23. ShadowWindow (Component* comp, const DropShadow& ds)
  24. : target (comp), shadow (ds)
  25. {
  26. setVisible (true);
  27. setAccessible (false);
  28. setInterceptsMouseClicks (false, false);
  29. if (comp->isOnDesktop())
  30. {
  31. setSize (1, 1); // to keep the OS happy by not having zero-size windows
  32. addToDesktop (ComponentPeer::windowIgnoresMouseClicks
  33. | ComponentPeer::windowIsTemporary
  34. | ComponentPeer::windowIgnoresKeyPresses);
  35. }
  36. else if (Component* const parent = comp->getParentComponent())
  37. {
  38. parent->addChildComponent (this);
  39. }
  40. }
  41. void paint (Graphics& g) override
  42. {
  43. if (Component* c = target)
  44. shadow.drawForRectangle (g, getLocalArea (c, c->getLocalBounds()));
  45. }
  46. void resized() override
  47. {
  48. repaint(); // (needed for correct repainting)
  49. }
  50. float getDesktopScaleFactor() const override
  51. {
  52. if (target != nullptr)
  53. return target->getDesktopScaleFactor();
  54. return Component::getDesktopScaleFactor();
  55. }
  56. private:
  57. WeakReference<Component> target;
  58. DropShadow shadow;
  59. JUCE_DECLARE_NON_COPYABLE (ShadowWindow)
  60. };
  61. //==============================================================================
  62. DropShadower::DropShadower (const DropShadow& ds) : shadow (ds) {}
  63. DropShadower::~DropShadower()
  64. {
  65. if (owner != nullptr)
  66. {
  67. owner->removeComponentListener (this);
  68. owner = nullptr;
  69. }
  70. updateParent();
  71. const ScopedValueSetter<bool> setter (reentrant, true);
  72. shadowWindows.clear();
  73. }
  74. void DropShadower::setOwner (Component* componentToFollow)
  75. {
  76. if (componentToFollow != owner)
  77. {
  78. if (owner != nullptr)
  79. owner->removeComponentListener (this);
  80. // (the component can't be null)
  81. jassert (componentToFollow != nullptr);
  82. owner = componentToFollow;
  83. jassert (owner != nullptr);
  84. updateParent();
  85. owner->addComponentListener (this);
  86. updateShadows();
  87. }
  88. }
  89. void DropShadower::updateParent()
  90. {
  91. if (Component* p = lastParentComp)
  92. p->removeComponentListener (this);
  93. lastParentComp = owner != nullptr ? owner->getParentComponent() : nullptr;
  94. if (Component* p = lastParentComp)
  95. p->addComponentListener (this);
  96. }
  97. void DropShadower::componentMovedOrResized (Component& c, bool /*wasMoved*/, bool /*wasResized*/)
  98. {
  99. if (owner == &c)
  100. updateShadows();
  101. }
  102. void DropShadower::componentBroughtToFront (Component& c)
  103. {
  104. if (owner == &c)
  105. updateShadows();
  106. }
  107. void DropShadower::componentChildrenChanged (Component&)
  108. {
  109. updateShadows();
  110. }
  111. void DropShadower::componentParentHierarchyChanged (Component& c)
  112. {
  113. if (owner == &c)
  114. {
  115. updateParent();
  116. updateShadows();
  117. }
  118. }
  119. void DropShadower::componentVisibilityChanged (Component& c)
  120. {
  121. if (owner == &c)
  122. updateShadows();
  123. }
  124. void DropShadower::updateShadows()
  125. {
  126. if (reentrant)
  127. return;
  128. const ScopedValueSetter<bool> setter (reentrant, true);
  129. if (owner == nullptr)
  130. {
  131. shadowWindows.clear();
  132. return;
  133. }
  134. if (owner->isShowing()
  135. && owner->getWidth() > 0 && owner->getHeight() > 0
  136. && (Desktop::canUseSemiTransparentWindows() || owner->getParentComponent() != nullptr))
  137. {
  138. while (shadowWindows.size() < 4)
  139. shadowWindows.add (new ShadowWindow (owner, shadow));
  140. const int shadowEdge = jmax (shadow.offset.x, shadow.offset.y) + shadow.radius;
  141. const int x = owner->getX();
  142. const int y = owner->getY() - shadowEdge;
  143. const int w = owner->getWidth();
  144. const int h = owner->getHeight() + shadowEdge + shadowEdge;
  145. for (int i = 4; --i >= 0;)
  146. {
  147. // there seem to be rare situations where the dropshadower may be deleted by
  148. // callbacks during this loop, so use a weak ref to watch out for this..
  149. WeakReference<Component> sw (shadowWindows[i]);
  150. if (sw != nullptr)
  151. {
  152. sw->setAlwaysOnTop (owner->isAlwaysOnTop());
  153. if (sw == nullptr)
  154. return;
  155. switch (i)
  156. {
  157. case 0: sw->setBounds (x - shadowEdge, y, shadowEdge, h); break;
  158. case 1: sw->setBounds (x + w, y, shadowEdge, h); break;
  159. case 2: sw->setBounds (x, y, w, shadowEdge); break;
  160. case 3: sw->setBounds (x, owner->getBottom(), w, shadowEdge); break;
  161. default: break;
  162. }
  163. if (sw == nullptr)
  164. return;
  165. sw->toBehind (i == 3 ? owner.get() : shadowWindows.getUnchecked (i + 1));
  166. }
  167. }
  168. }
  169. else
  170. {
  171. shadowWindows.clear();
  172. }
  173. }
  174. } // namespace juce