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.

264 lines
7.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  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 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. #pragma once
  20. //==============================================================================
  21. class ConcertinaHeader : public Component,
  22. public ChangeBroadcaster
  23. {
  24. public:
  25. ConcertinaHeader (String n, Path p)
  26. : Component (n), name (n), iconPath (p)
  27. {
  28. panelIcon = Icon (iconPath, Colours::white);
  29. nameLabel.setText (name, dontSendNotification);
  30. nameLabel.setJustificationType (Justification::centredLeft);
  31. nameLabel.setInterceptsMouseClicks (false, false);
  32. nameLabel.setColour (Label::textColourId, Colours::white);
  33. addAndMakeVisible (nameLabel);
  34. }
  35. void resized() override
  36. {
  37. auto b = getLocalBounds().toFloat();
  38. iconBounds = b.removeFromLeft (b.getHeight()).reduced (7, 7);
  39. arrowBounds = b.removeFromRight (b.getHeight());
  40. nameLabel.setBounds (b.toNearestInt());
  41. }
  42. void paint (Graphics& g) override
  43. {
  44. g.setColour (findColour (defaultButtonBackgroundColourId));
  45. g.fillRoundedRectangle (getLocalBounds().reduced (2, 3).toFloat(), 2.0f);
  46. g.setColour (Colours::white);
  47. g.fillPath (arrowPath = ProjucerLookAndFeel::getArrowPath (arrowBounds,
  48. getParentComponent()->getBoundsInParent().getY() == yPosition ? 2 : 0,
  49. true, Justification::centred));
  50. panelIcon.draw (g, iconBounds.toFloat(), false);
  51. }
  52. void mouseUp (const MouseEvent& e) override
  53. {
  54. if (! e.mouseWasDraggedSinceMouseDown())
  55. sendChangeMessage();
  56. }
  57. int direction = 0;
  58. int yPosition = 0;
  59. private:
  60. String name;
  61. Label nameLabel;
  62. Path iconPath;
  63. Icon panelIcon;
  64. Rectangle<float> arrowBounds, iconBounds;
  65. Path arrowPath;
  66. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConcertinaHeader)
  67. };
  68. //==============================================================================
  69. class FindPanel : public Component,
  70. private Timer,
  71. private FocusChangeListener
  72. {
  73. public:
  74. FindPanel (std::function<void (const String&)> cb)
  75. : callback (cb)
  76. {
  77. addAndMakeVisible (editor);
  78. editor.onTextChange = [this] { startTimer (250); };
  79. editor.onFocusLost = [this]
  80. {
  81. isFocused = false;
  82. repaint();
  83. };
  84. Desktop::getInstance().addFocusChangeListener (this);
  85. lookAndFeelChanged();
  86. }
  87. ~FindPanel() override
  88. {
  89. Desktop::getInstance().removeFocusChangeListener (this);
  90. }
  91. void paintOverChildren (Graphics& g) override
  92. {
  93. if (! isFocused)
  94. return;
  95. g.setColour (findColour (defaultHighlightColourId));
  96. Path p;
  97. p.addRoundedRectangle (getLocalBounds().reduced (2), 3.0f);
  98. g.strokePath (p, PathStrokeType (2.0f));
  99. }
  100. void resized() override
  101. {
  102. editor.setBounds (getLocalBounds().reduced (2));
  103. }
  104. private:
  105. TextEditor editor;
  106. bool isFocused = false;
  107. std::function<void (const String&)> callback;
  108. //==============================================================================
  109. void lookAndFeelChanged() override
  110. {
  111. editor.setTextToShowWhenEmpty ("Filter...", findColour (widgetTextColourId).withAlpha (0.3f));
  112. }
  113. void globalFocusChanged (Component* focusedComponent) override
  114. {
  115. if (focusedComponent == &editor)
  116. {
  117. isFocused = true;
  118. repaint();
  119. }
  120. }
  121. void timerCallback() override
  122. {
  123. stopTimer();
  124. callback (editor.getText());
  125. }
  126. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FindPanel)
  127. };
  128. //==============================================================================
  129. class ConcertinaTreeComponent : public Component
  130. {
  131. public:
  132. ConcertinaTreeComponent (TreePanelBase* tree, bool hasAddButton = false,
  133. bool hasSettingsButton = false, bool hasFindPanel = false)
  134. : treeToDisplay (tree)
  135. {
  136. if (hasAddButton)
  137. {
  138. addButton.reset (new IconButton ("Add", &getIcons().plus));
  139. addAndMakeVisible (addButton.get());
  140. addButton->onClick = [this] { showAddMenu(); };
  141. }
  142. if (hasSettingsButton)
  143. {
  144. settingsButton.reset (new IconButton ("Settings", &getIcons().settings));
  145. addAndMakeVisible (settingsButton.get());
  146. settingsButton->onClick = [this] { showSettings(); };
  147. }
  148. if (hasFindPanel)
  149. {
  150. findPanel.reset (new FindPanel ([this] (const String& filter) { treeToDisplay->rootItem->setSearchFilter (filter); }));
  151. addAndMakeVisible (findPanel.get());
  152. }
  153. addAndMakeVisible (treeToDisplay.get());
  154. }
  155. ~ConcertinaTreeComponent() override
  156. {
  157. treeToDisplay.reset();
  158. addButton.reset();
  159. findPanel.reset();
  160. settingsButton.reset();
  161. }
  162. void resized() override
  163. {
  164. auto bounds = getLocalBounds();
  165. if (addButton != nullptr || settingsButton != nullptr || findPanel != nullptr)
  166. {
  167. auto bottomSlice = bounds.removeFromBottom (25);
  168. bottomSlice.removeFromRight (3);
  169. if (addButton != nullptr)
  170. addButton->setBounds (bottomSlice.removeFromRight (25).reduced (2));
  171. if (settingsButton != nullptr)
  172. settingsButton->setBounds (bottomSlice.removeFromRight (25).reduced (2));
  173. if (findPanel != nullptr)
  174. findPanel->setBounds (bottomSlice.reduced (2));
  175. }
  176. treeToDisplay->setBounds (bounds);
  177. }
  178. TreePanelBase* getTree() const noexcept { return treeToDisplay.get(); }
  179. private:
  180. std::unique_ptr<TreePanelBase> treeToDisplay;
  181. std::unique_ptr<IconButton> addButton, settingsButton;
  182. std::unique_ptr<FindPanel> findPanel;
  183. void showAddMenu()
  184. {
  185. auto numSelected = treeToDisplay->tree.getNumSelectedItems();
  186. if (numSelected > 1)
  187. return;
  188. if (numSelected == 0)
  189. {
  190. if (auto* root = dynamic_cast<JucerTreeViewBase*> (treeToDisplay->tree.getRootItem()))
  191. root->showPopupMenu();
  192. }
  193. else
  194. {
  195. if (auto* item = dynamic_cast<JucerTreeViewBase*> (treeToDisplay->tree.getSelectedItem (0)))
  196. item->showAddMenu();
  197. }
  198. }
  199. void showSettings()
  200. {
  201. if (auto* root = dynamic_cast<JucerTreeViewBase*> (treeToDisplay->tree.getRootItem()))
  202. {
  203. treeToDisplay->tree.clearSelectedItems();
  204. root->showDocument();
  205. }
  206. }
  207. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConcertinaTreeComponent)
  208. };