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.

256 lines
7.8KB

  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. ToolbarItemFactory::ToolbarItemFactory() {}
  21. ToolbarItemFactory::~ToolbarItemFactory() {}
  22. //==============================================================================
  23. class ToolbarItemComponent::ItemDragAndDropOverlayComponent : public Component
  24. {
  25. public:
  26. ItemDragAndDropOverlayComponent()
  27. : isDragging (false)
  28. {
  29. setAlwaysOnTop (true);
  30. setRepaintsOnMouseActivity (true);
  31. setMouseCursor (MouseCursor::DraggingHandCursor);
  32. }
  33. void paint (Graphics& g) override
  34. {
  35. if (ToolbarItemComponent* const tc = getToolbarItemComponent())
  36. {
  37. if (isMouseOverOrDragging()
  38. && tc->getEditingMode() == ToolbarItemComponent::editableOnToolbar)
  39. {
  40. g.setColour (findColour (Toolbar::editingModeOutlineColourId, true));
  41. g.drawRect (getLocalBounds(), jmin (2, (getWidth() - 1) / 2,
  42. (getHeight() - 1) / 2));
  43. }
  44. }
  45. }
  46. void mouseDown (const MouseEvent& e) override
  47. {
  48. isDragging = false;
  49. if (ToolbarItemComponent* const tc = getToolbarItemComponent())
  50. {
  51. tc->dragOffsetX = e.x;
  52. tc->dragOffsetY = e.y;
  53. }
  54. }
  55. void mouseDrag (const MouseEvent& e) override
  56. {
  57. if (e.mouseWasDraggedSinceMouseDown() && ! isDragging)
  58. {
  59. isDragging = true;
  60. if (DragAndDropContainer* const dnd = DragAndDropContainer::findParentDragContainerFor (this))
  61. {
  62. dnd->startDragging (Toolbar::toolbarDragDescriptor, getParentComponent(), ScaledImage(), true, nullptr, &e.source);
  63. if (ToolbarItemComponent* const tc = getToolbarItemComponent())
  64. {
  65. tc->isBeingDragged = true;
  66. if (tc->getEditingMode() == ToolbarItemComponent::editableOnToolbar)
  67. tc->setVisible (false);
  68. }
  69. }
  70. }
  71. }
  72. void mouseUp (const MouseEvent&) override
  73. {
  74. isDragging = false;
  75. if (ToolbarItemComponent* const tc = getToolbarItemComponent())
  76. {
  77. tc->isBeingDragged = false;
  78. if (Toolbar* const tb = tc->getToolbar())
  79. tb->updateAllItemPositions (true);
  80. else if (tc->getEditingMode() == ToolbarItemComponent::editableOnToolbar)
  81. delete tc;
  82. }
  83. }
  84. void parentSizeChanged() override
  85. {
  86. setBounds (0, 0, getParentWidth(), getParentHeight());
  87. }
  88. private:
  89. //==============================================================================
  90. bool isDragging;
  91. ToolbarItemComponent* getToolbarItemComponent() const noexcept
  92. {
  93. return dynamic_cast<ToolbarItemComponent*> (getParentComponent());
  94. }
  95. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ItemDragAndDropOverlayComponent)
  96. };
  97. //==============================================================================
  98. ToolbarItemComponent::ToolbarItemComponent (const int itemId_,
  99. const String& labelText,
  100. const bool isBeingUsedAsAButton_)
  101. : Button (labelText),
  102. itemId (itemId_),
  103. mode (normalMode),
  104. toolbarStyle (Toolbar::iconsOnly),
  105. dragOffsetX (0),
  106. dragOffsetY (0),
  107. isActive (true),
  108. isBeingDragged (false),
  109. isBeingUsedAsAButton (isBeingUsedAsAButton_)
  110. {
  111. // Your item ID can't be 0!
  112. jassert (itemId_ != 0);
  113. }
  114. ToolbarItemComponent::~ToolbarItemComponent()
  115. {
  116. overlayComp.reset();
  117. }
  118. Toolbar* ToolbarItemComponent::getToolbar() const
  119. {
  120. return dynamic_cast<Toolbar*> (getParentComponent());
  121. }
  122. bool ToolbarItemComponent::isToolbarVertical() const
  123. {
  124. const Toolbar* const t = getToolbar();
  125. return t != nullptr && t->isVertical();
  126. }
  127. void ToolbarItemComponent::setStyle (const Toolbar::ToolbarItemStyle& newStyle)
  128. {
  129. if (toolbarStyle != newStyle)
  130. {
  131. toolbarStyle = newStyle;
  132. repaint();
  133. resized();
  134. }
  135. }
  136. void ToolbarItemComponent::paintButton (Graphics& g, const bool over, const bool down)
  137. {
  138. if (isBeingUsedAsAButton)
  139. getLookAndFeel().paintToolbarButtonBackground (g, getWidth(), getHeight(),
  140. over, down, *this);
  141. if (toolbarStyle != Toolbar::iconsOnly)
  142. {
  143. auto indent = contentArea.getX();
  144. auto y = indent;
  145. auto h = getHeight() - indent * 2;
  146. if (toolbarStyle == Toolbar::iconsWithText)
  147. {
  148. y = contentArea.getBottom() + indent / 2;
  149. h -= contentArea.getHeight();
  150. }
  151. getLookAndFeel().paintToolbarButtonLabel (g, indent, y, getWidth() - indent * 2, h,
  152. getButtonText(), *this);
  153. }
  154. if (! contentArea.isEmpty())
  155. {
  156. Graphics::ScopedSaveState ss (g);
  157. g.reduceClipRegion (contentArea);
  158. g.setOrigin (contentArea.getPosition());
  159. paintButtonArea (g, contentArea.getWidth(), contentArea.getHeight(), over, down);
  160. }
  161. }
  162. void ToolbarItemComponent::resized()
  163. {
  164. if (toolbarStyle != Toolbar::textOnly)
  165. {
  166. const int indent = jmin (proportionOfWidth (0.08f),
  167. proportionOfHeight (0.08f));
  168. contentArea = Rectangle<int> (indent, indent,
  169. getWidth() - indent * 2,
  170. toolbarStyle == Toolbar::iconsWithText ? proportionOfHeight (0.55f)
  171. : (getHeight() - indent * 2));
  172. }
  173. else
  174. {
  175. contentArea = {};
  176. }
  177. contentAreaChanged (contentArea);
  178. }
  179. void ToolbarItemComponent::setEditingMode (const ToolbarEditingMode newMode)
  180. {
  181. if (mode != newMode)
  182. {
  183. mode = newMode;
  184. repaint();
  185. if (mode == normalMode)
  186. {
  187. overlayComp.reset();
  188. }
  189. else if (overlayComp == nullptr)
  190. {
  191. overlayComp.reset (new ItemDragAndDropOverlayComponent());
  192. addAndMakeVisible (overlayComp.get());
  193. overlayComp->parentSizeChanged();
  194. }
  195. resized();
  196. }
  197. }
  198. //==============================================================================
  199. std::unique_ptr<AccessibilityHandler> ToolbarItemComponent::createAccessibilityHandler()
  200. {
  201. const auto shouldItemBeAccessible = (itemId != ToolbarItemFactory::separatorBarId
  202. && itemId != ToolbarItemFactory::spacerId
  203. && itemId != ToolbarItemFactory::flexibleSpacerId);
  204. if (! shouldItemBeAccessible)
  205. return nullptr;
  206. return std::make_unique<ButtonAccessibilityHandler> (*this, AccessibilityRole::button);
  207. }
  208. } // namespace juce