Audio plugin host https://kx.studio/carla
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.

juce_SidePanel.cpp 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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. SidePanel::SidePanel (StringRef title, int width, bool positionOnLeft,
  21. Component* contentToDisplay, bool deleteComponentWhenNoLongerNeeded)
  22. : titleLabel ("titleLabel", title),
  23. isOnLeft (positionOnLeft),
  24. panelWidth (width)
  25. {
  26. lookAndFeelChanged();
  27. addAndMakeVisible (titleLabel);
  28. dismissButton.onClick = [this] { showOrHide (false); };
  29. addAndMakeVisible (dismissButton);
  30. Desktop::getInstance().addGlobalMouseListener (this);
  31. if (contentToDisplay != nullptr)
  32. setContent (contentToDisplay, deleteComponentWhenNoLongerNeeded);
  33. setOpaque (false);
  34. }
  35. SidePanel::~SidePanel()
  36. {
  37. Desktop::getInstance().removeGlobalMouseListener (this);
  38. if (parent != nullptr)
  39. parent->removeComponentListener (this);
  40. }
  41. void SidePanel::setContent (Component* newContent, bool deleteComponentWhenNoLongerNeeded)
  42. {
  43. if (contentComponent.get() != newContent)
  44. {
  45. if (deleteComponentWhenNoLongerNeeded)
  46. contentComponent.setOwned (newContent);
  47. else
  48. contentComponent.setNonOwned (newContent);
  49. addAndMakeVisible (contentComponent);
  50. resized();
  51. }
  52. }
  53. void SidePanel::setTitleBarComponent (Component* titleBarComponentToUse,
  54. bool keepDismissButton,
  55. bool deleteComponentWhenNoLongerNeeded)
  56. {
  57. if (titleBarComponent.get() != titleBarComponentToUse)
  58. {
  59. if (deleteComponentWhenNoLongerNeeded)
  60. titleBarComponent.setOwned (titleBarComponentToUse);
  61. else
  62. titleBarComponent.setNonOwned (titleBarComponentToUse);
  63. addAndMakeVisible (titleBarComponent);
  64. resized();
  65. }
  66. shouldShowDismissButton = keepDismissButton;
  67. }
  68. void SidePanel::showOrHide (bool show)
  69. {
  70. if (parent != nullptr)
  71. {
  72. isShowing = show;
  73. Desktop::getInstance().getAnimator().animateComponent (this, calculateBoundsInParent (*parent),
  74. 1.0f, 250, true, 1.0, 0.0);
  75. if (onPanelShowHide != nullptr)
  76. onPanelShowHide (isShowing);
  77. }
  78. }
  79. void SidePanel::moved()
  80. {
  81. if (onPanelMove != nullptr)
  82. onPanelMove();
  83. }
  84. void SidePanel::resized()
  85. {
  86. auto bounds = getLocalBounds();
  87. calculateAndRemoveShadowBounds (bounds);
  88. auto titleBounds = bounds.removeFromTop (titleBarHeight);
  89. if (titleBarComponent != nullptr)
  90. {
  91. if (shouldShowDismissButton)
  92. dismissButton.setBounds (isOnLeft ? titleBounds.removeFromRight (30).withTrimmedRight (10)
  93. : titleBounds.removeFromLeft (30).withTrimmedLeft (10));
  94. titleBarComponent->setBounds (titleBounds);
  95. }
  96. else
  97. {
  98. dismissButton.setBounds (isOnLeft ? titleBounds.removeFromRight (30).withTrimmedRight (10)
  99. : titleBounds.removeFromLeft (30).withTrimmedLeft (10));
  100. titleLabel.setBounds (isOnLeft ? titleBounds.withTrimmedRight (40)
  101. : titleBounds.withTrimmedLeft (40));
  102. }
  103. if (contentComponent != nullptr)
  104. contentComponent->setBounds (bounds);
  105. }
  106. void SidePanel::paint (Graphics& g)
  107. {
  108. auto& lf = getLookAndFeel();
  109. auto bgColour = lf.findColour (SidePanel::backgroundColour);
  110. auto shadowColour = lf.findColour (SidePanel::shadowBaseColour);
  111. g.setGradientFill (ColourGradient (shadowColour.withAlpha (0.7f), (isOnLeft ? shadowArea.getTopLeft()
  112. : shadowArea.getTopRight()).toFloat(),
  113. shadowColour.withAlpha (0.0f), (isOnLeft ? shadowArea.getTopRight()
  114. : shadowArea.getTopLeft()).toFloat(), false));
  115. g.fillRect (shadowArea);
  116. g.excludeClipRegion (shadowArea);
  117. g.fillAll (bgColour);
  118. }
  119. void SidePanel::parentHierarchyChanged()
  120. {
  121. auto* newParent = getParentComponent();
  122. if ((newParent != nullptr) && (parent != newParent))
  123. {
  124. if (parent != nullptr)
  125. parent->removeComponentListener (this);
  126. parent = newParent;
  127. parent->addComponentListener (this);
  128. }
  129. }
  130. void SidePanel::mouseDrag (const MouseEvent& e)
  131. {
  132. if (shouldResize)
  133. {
  134. Point<int> convertedPoint;
  135. if (getParentComponent() == nullptr)
  136. convertedPoint = e.eventComponent->localPointToGlobal (e.getPosition());
  137. else
  138. convertedPoint = getParentComponent()->getLocalPoint (e.eventComponent, e.getPosition());
  139. auto currentMouseDragX = convertedPoint.x;
  140. if (isOnLeft)
  141. {
  142. amountMoved = startingBounds.getRight() - currentMouseDragX;
  143. setBounds (getBounds().withX (startingBounds.getX() - jmax (amountMoved, 0)));
  144. }
  145. else
  146. {
  147. amountMoved = currentMouseDragX - startingBounds.getX();
  148. setBounds (getBounds().withX (startingBounds.getX() + jmax (amountMoved, 0)));
  149. }
  150. }
  151. else if (isShowing)
  152. {
  153. auto relativeMouseDownPosition = getLocalPoint (e.eventComponent, e.getMouseDownPosition());
  154. auto relativeMouseDragPosition = getLocalPoint (e.eventComponent, e.getPosition());
  155. if (! getLocalBounds().contains (relativeMouseDownPosition)
  156. && getLocalBounds().contains (relativeMouseDragPosition))
  157. {
  158. shouldResize = true;
  159. startingBounds = getBounds();
  160. }
  161. }
  162. }
  163. void SidePanel::mouseUp (const MouseEvent&)
  164. {
  165. if (shouldResize)
  166. {
  167. showOrHide (amountMoved < (panelWidth / 2));
  168. amountMoved = 0;
  169. shouldResize = false;
  170. }
  171. }
  172. //==============================================================================
  173. void SidePanel::lookAndFeelChanged()
  174. {
  175. auto& lf = getLookAndFeel();
  176. dismissButton.setShape (lf.getSidePanelDismissButtonShape (*this), false, true, false);
  177. dismissButton.setColours (lf.findColour (SidePanel::dismissButtonNormalColour),
  178. lf.findColour (SidePanel::dismissButtonOverColour),
  179. lf.findColour (SidePanel::dismissButtonDownColour));
  180. titleLabel.setFont (lf.getSidePanelTitleFont (*this));
  181. titleLabel.setColour (Label::textColourId, findColour (SidePanel::titleTextColour));
  182. titleLabel.setJustificationType (lf.getSidePanelTitleJustification (*this));
  183. }
  184. void SidePanel::componentMovedOrResized (Component& component, bool wasMoved, bool wasResized)
  185. {
  186. ignoreUnused (wasMoved);
  187. if (wasResized && (&component == parent))
  188. setBounds (calculateBoundsInParent (component));
  189. }
  190. Rectangle<int> SidePanel::calculateBoundsInParent (Component& parentComp) const
  191. {
  192. auto parentBounds = parentComp.getLocalBounds();
  193. if (isOnLeft)
  194. {
  195. return isShowing ? parentBounds.removeFromLeft (panelWidth)
  196. : parentBounds.withX (parentBounds.getX() - panelWidth).withWidth (panelWidth);
  197. }
  198. return isShowing ? parentBounds.removeFromRight (panelWidth)
  199. : parentBounds.withX (parentBounds.getRight()).withWidth (panelWidth);
  200. }
  201. void SidePanel::calculateAndRemoveShadowBounds (Rectangle<int>& bounds)
  202. {
  203. shadowArea = isOnLeft ? bounds.removeFromRight (shadowWidth)
  204. : bounds.removeFromLeft (shadowWidth);
  205. }
  206. bool SidePanel::isMouseEventInThisOrChildren (Component* eventComponent)
  207. {
  208. if (eventComponent == this)
  209. return true;
  210. for (auto& child : getChildren())
  211. if (eventComponent == child)
  212. return true;
  213. return false;
  214. }
  215. } // namespace juce