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.

239 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - 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 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-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. //==============================================================================
  21. /**
  22. A component that is positioned on either the left- or right-hand side of its parent,
  23. containing a header and some content. This sort of component is typically used for
  24. navigation and forms in mobile applications.
  25. When triggered with the showOrHide() method, the SidePanel will animate itself to its
  26. new position. This component also contains some logic to reactively resize and dismiss
  27. itself when the user drags it.
  28. @tags{GUI}
  29. */
  30. class SidePanel : public Component,
  31. private ComponentListener,
  32. private ChangeListener
  33. {
  34. public:
  35. //==============================================================================
  36. /** Creates a SidePanel component.
  37. @param title the text to use for the SidePanel's title bar
  38. @param width the width of the SidePanel
  39. @param positionOnLeft if true, the SidePanel will be positioned on the left of its parent component and
  40. if false, the SidePanel will be positioned on the right of its parent component
  41. @param contentComponent the component to add to this SidePanel - this content will take up the full
  42. size of the SidePanel, minus the height of the title bar. You can pass nullptr
  43. to this if you like and set the content component later using the setContent() method
  44. @param deleteComponentWhenNoLongerNeeded if true, the component will be deleted automatically when
  45. the SidePanel is deleted or when a different component is added. If false,
  46. the caller must manage the lifetime of the component
  47. */
  48. SidePanel (StringRef title, int width, bool positionOnLeft,
  49. Component* contentComponent = nullptr,
  50. bool deleteComponentWhenNoLongerNeeded = true);
  51. /** Destructor */
  52. ~SidePanel() override;
  53. //==============================================================================
  54. /** Sets the component that this SidePanel will contain.
  55. This will add the given component to this SidePanel and position it below the title bar.
  56. (Don't add or remove any child components directly using the normal
  57. Component::addChildComponent() methods).
  58. @param newContentComponent the component to add to this SidePanel, or nullptr to remove
  59. the current component.
  60. @param deleteComponentWhenNoLongerNeeded if true, the component will be deleted automatically when
  61. the SidePanel is deleted or when a different component is added. If false,
  62. the caller must manage the lifetime of the component
  63. @see getContent
  64. */
  65. void setContent (Component* newContentComponent,
  66. bool deleteComponentWhenNoLongerNeeded = true);
  67. /** Returns the component that's currently being used inside the SidePanel.
  68. @see setViewedComponent
  69. */
  70. Component* getContent() const noexcept { return contentComponent.get(); }
  71. /** Sets a custom component to be used for the title bar of this SidePanel, replacing
  72. the default. You can pass a nullptr to revert to the default title bar.
  73. @param titleBarComponentToUse the component to use as the title bar, or nullptr to use
  74. the default
  75. @param keepDismissButton if false the specified component will take up the full width of
  76. the title bar including the dismiss button but if true, the default
  77. dismiss button will be kept
  78. @param deleteComponentWhenNoLongerNeeded if true, the component will be deleted automatically when
  79. the SidePanel is deleted or when a different component is added. If false,
  80. the caller must manage the lifetime of the component
  81. @see getTitleBarComponent
  82. */
  83. void setTitleBarComponent (Component* titleBarComponentToUse,
  84. bool keepDismissButton,
  85. bool deleteComponentWhenNoLongerNeeded = true);
  86. /** Returns the component that is currently being used as the title bar of the SidePanel.
  87. @see setTitleBarComponent
  88. */
  89. Component* getTitleBarComponent() const noexcept { return titleBarComponent.get(); }
  90. /** Shows or hides the SidePanel.
  91. This will animate the SidePanel to either its full width or to be hidden on the
  92. left- or right-hand side of its parent component depending on the value of positionOnLeft
  93. that was passed to the constructor.
  94. @param show if true, this will show the SidePanel and if false the SidePanel will be hidden
  95. */
  96. void showOrHide (bool show);
  97. //==============================================================================
  98. /** Returns true if the SidePanel is currently showing. */
  99. bool isPanelShowing() const noexcept { return isShowing; }
  100. /** Returns true if the SidePanel is positioned on the left of its parent. */
  101. bool isPanelOnLeft() const noexcept { return isOnLeft; }
  102. /** Sets the width of the shadow that will be drawn on the side of the panel. */
  103. void setShadowWidth (int newWidth) noexcept { shadowWidth = newWidth; }
  104. /** Returns the width of the shadow that will be drawn on the side of the panel. */
  105. int getShadowWidth() const noexcept { return shadowWidth; }
  106. /** Sets the height of the title bar at the top of the SidePanel. */
  107. void setTitleBarHeight (int newHeight) noexcept { titleBarHeight = newHeight; }
  108. /** Returns the height of the title bar at the top of the SidePanel. */
  109. int getTitleBarHeight() const noexcept { return titleBarHeight; }
  110. /** Returns the text that is displayed in the title bar at the top of the SidePanel. */
  111. String getTitleText() const noexcept { return titleLabel.getText(); }
  112. //==============================================================================
  113. /** This abstract base class is implemented by LookAndFeel classes to provide
  114. SidePanel drawing functionality.
  115. */
  116. struct JUCE_API LookAndFeelMethods
  117. {
  118. virtual ~LookAndFeelMethods() = default;
  119. virtual Font getSidePanelTitleFont (SidePanel&) = 0;
  120. virtual Justification getSidePanelTitleJustification (SidePanel&) = 0;
  121. virtual Path getSidePanelDismissButtonShape (SidePanel&) = 0;
  122. };
  123. /** A set of colour IDs to use to change the colour of various aspects of the SidePanel.
  124. These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
  125. methods.
  126. @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
  127. */
  128. enum ColourIds
  129. {
  130. backgroundColour = 0x100f001,
  131. titleTextColour = 0x100f002,
  132. shadowBaseColour = 0x100f003,
  133. dismissButtonNormalColour = 0x100f004,
  134. dismissButtonOverColour = 0x100f005,
  135. dismissButtonDownColour = 0x100f006
  136. };
  137. //==============================================================================
  138. /** You can assign a lambda to this callback object and it will be called when the panel is moved. */
  139. std::function<void()> onPanelMove;
  140. /** You can assign a lambda to this callback object and it will be called when the panel is shown or hidden. */
  141. std::function<void (bool)> onPanelShowHide;
  142. //==============================================================================
  143. /** @internal */
  144. void moved() override;
  145. /** @internal */
  146. void resized() override;
  147. /** @internal */
  148. void paint (Graphics& g) override;
  149. /** @internal */
  150. void parentHierarchyChanged() override;
  151. /** @internal */
  152. void mouseDrag (const MouseEvent&) override;
  153. /** @internal */
  154. void mouseUp (const MouseEvent&) override;
  155. private:
  156. //==============================================================================
  157. Component* parent = nullptr;
  158. OptionalScopedPointer<Component> contentComponent;
  159. OptionalScopedPointer<Component> titleBarComponent;
  160. Label titleLabel;
  161. ShapeButton dismissButton { "dismissButton", Colours::lightgrey, Colours::lightgrey, Colours::white };
  162. Rectangle<int> shadowArea;
  163. bool isOnLeft = false;
  164. bool isShowing = false;
  165. int panelWidth = 0;
  166. int shadowWidth = 15;
  167. int titleBarHeight = 40;
  168. Rectangle<int> startingBounds;
  169. bool shouldResize = false;
  170. int amountMoved = 0;
  171. bool shouldShowDismissButton = true;
  172. //==============================================================================
  173. std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
  174. void lookAndFeelChanged() override;
  175. void componentMovedOrResized (Component&, bool wasMoved, bool wasResized) override;
  176. void changeListenerCallback (ChangeBroadcaster*) override;
  177. Rectangle<int> calculateBoundsInParent (Component&) const;
  178. void calculateAndRemoveShadowBounds (Rectangle<int>& bounds);
  179. bool isMouseEventInThisOrChildren (Component*);
  180. //==============================================================================
  181. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SidePanel)
  182. };
  183. } // namespace juce