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.

269 lines
8.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. //==============================================================================
  18. class InfoButton : public Button
  19. {
  20. public:
  21. InfoButton (PropertyComponent& comp)
  22. : Button (String()),
  23. associatedComponent (comp)
  24. {
  25. tooltip = associatedComponent.getTooltip();
  26. auto stringWidth = Font (14.0f).getStringWidthFloat (tooltip);
  27. int maxWidth = 300;
  28. if (stringWidth > maxWidth)
  29. {
  30. width = maxWidth;
  31. numLines += static_cast<int> (stringWidth / width);
  32. }
  33. else
  34. {
  35. width = roundToInt (stringWidth);
  36. }
  37. }
  38. void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) override
  39. {
  40. auto bounds = getLocalBounds().toFloat().reduced (2);
  41. const auto& icon = getIcons().info;
  42. g.setColour (findColour (treeIconColourId).withMultipliedAlpha (isMouseOverButton || isButtonDown ? 1.0f : 0.5f));
  43. if (isButtonDown)
  44. g.fillEllipse (bounds);
  45. else
  46. g.fillPath (icon, RectanglePlacement (RectanglePlacement::centred)
  47. .getTransformToFit (icon.getBounds(), bounds));
  48. }
  49. void clicked() override
  50. {
  51. auto* w = new InfoWindow (tooltip);
  52. w->setSize (width, w->getHeight() * numLines + 10);
  53. CallOutBox::launchAsynchronously (w, getScreenBounds(), nullptr);
  54. }
  55. PropertyComponent& associatedComponent;
  56. private:
  57. String tooltip;
  58. int width;
  59. int numLines = 1;
  60. //==============================================================================
  61. struct InfoWindow : public Component
  62. {
  63. InfoWindow (String s)
  64. : stringToDisplay (s)
  65. {
  66. setSize (150, 14);
  67. }
  68. void paint (Graphics& g) override
  69. {
  70. g.fillAll (findColour (secondaryBackgroundColourId));
  71. g.setColour (findColour (defaultTextColourId));
  72. g.setFont (Font (14.0f));
  73. g.drawFittedText (stringToDisplay, getLocalBounds(), Justification::centred, 10, 1.0f);
  74. }
  75. String stringToDisplay;
  76. };
  77. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InfoButton)
  78. };
  79. //==============================================================================
  80. class PropertyGroupComponent : public Component
  81. {
  82. public:
  83. PropertyGroupComponent (String name, Icon icon)
  84. : header (name, icon)
  85. {
  86. addAndMakeVisible (header);
  87. }
  88. void setProperties (const PropertyListBuilder& newProps)
  89. {
  90. infoButtons.clear();
  91. properties.clear();
  92. properties.addArray (newProps.components);
  93. for (auto i = properties.size(); --i >= 0;)
  94. {
  95. auto* prop = properties.getUnchecked (i);
  96. addAndMakeVisible (prop);
  97. if (! prop->getTooltip().isEmpty())
  98. {
  99. addAndMakeVisible (infoButtons.add (new InfoButton (*prop)));
  100. prop->setTooltip (String()); // set the tooltip to empty so it only displays when its button is clicked
  101. }
  102. }
  103. }
  104. int updateSize (int x, int y, int width)
  105. {
  106. header.setBounds (0, 0, width, 40);
  107. auto height = header.getHeight() + 5;
  108. for (auto i = 0; i < properties.size(); ++i)
  109. {
  110. auto* pp = properties.getUnchecked (i);
  111. auto propertyHeight = pp->getPreferredHeight() + (getHeightMultiplier (pp) * pp->getPreferredHeight());
  112. InfoButton* buttonToUse = nullptr;
  113. for (auto* b : infoButtons)
  114. if (&b->associatedComponent == pp)
  115. buttonToUse = b;
  116. if (buttonToUse != nullptr)
  117. {
  118. buttonToUse->setSize (20, 20);
  119. buttonToUse->setCentrePosition (20, height + (propertyHeight / 2));
  120. }
  121. pp->setBounds (40, height, width - 50, propertyHeight);
  122. resizeContentIfChoicePropertyComponent (pp);
  123. height += pp->getHeight() + 10;
  124. }
  125. height += 16;
  126. setBounds (x, y, width, jmax (height, getParentHeight()));
  127. return height;
  128. }
  129. void paint (Graphics& g) override
  130. {
  131. g.setColour (findColour (secondaryBackgroundColourId));
  132. g.fillRect (getLocalBounds());
  133. }
  134. int getHeightMultiplier (PropertyComponent* pp)
  135. {
  136. auto availableTextWidth = ProjucerLookAndFeel::getTextWidthForPropertyComponent (pp);
  137. auto font = ProjucerLookAndFeel::getPropertyComponentFont();
  138. auto nameWidth = font.getStringWidthFloat (pp->getName());
  139. return static_cast<int> (nameWidth / availableTextWidth);
  140. }
  141. void resizeContentIfChoicePropertyComponent (PropertyComponent* pp)
  142. {
  143. if (auto* choiceComp = dynamic_cast<ChoicePropertyComponent*> (pp))
  144. {
  145. auto* box = choiceComp->getChildComponent (0);
  146. auto bounds = box->getBounds();
  147. box->setBounds (bounds.withSizeKeepingCentre (box->getWidth(), pp->getPreferredHeight()));
  148. }
  149. }
  150. OwnedArray<PropertyComponent> properties;
  151. OwnedArray<InfoButton> infoButtons;
  152. ContentViewHeader header;
  153. private:
  154. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertyGroupComponent)
  155. };
  156. //==============================================================================
  157. class ConfigTreeItemBase : public JucerTreeViewBase,
  158. public ValueTree::Listener
  159. {
  160. public:
  161. ConfigTreeItemBase() {}
  162. void showSettingsPage (Component* content)
  163. {
  164. content->setComponentID (getUniqueName());
  165. ScopedPointer<Component> comp (content);
  166. if (ProjectContentComponent* pcc = getProjectContentComponent())
  167. pcc->setEditorComponent (comp.release(), nullptr);
  168. }
  169. void closeSettingsPage()
  170. {
  171. if (ProjectContentComponent* pcc = getProjectContentComponent())
  172. {
  173. if (auto* content = dynamic_cast<Viewport*> (pcc->getEditorComponent()))
  174. if (content->getViewedComponent()->getComponentID() == getUniqueName())
  175. pcc->hideEditor();
  176. }
  177. }
  178. void deleteAllSelectedItems() override
  179. {
  180. TreeView* const tree = getOwnerView();
  181. jassert (tree->getNumSelectedItems() <= 1); // multi-select should be disabled
  182. if (ConfigTreeItemBase* s = dynamic_cast<ConfigTreeItemBase*> (tree->getSelectedItem (0)))
  183. s->deleteItem();
  184. }
  185. void itemOpennessChanged (bool isNowOpen) override
  186. {
  187. if (isNowOpen)
  188. refreshSubItems();
  189. }
  190. void valueTreePropertyChanged (ValueTree&, const Identifier&) override {}
  191. void valueTreeChildAdded (ValueTree&, ValueTree&) override {}
  192. void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override {}
  193. void valueTreeChildOrderChanged (ValueTree&, int, int) override {}
  194. void valueTreeParentChanged (ValueTree&) override {}
  195. virtual bool isProjectSettings() const { return false; }
  196. virtual bool isModulesList() const { return false; }
  197. static void updateSize (Component& comp, PropertyGroupComponent& group)
  198. {
  199. const auto width = jmax (550, comp.getParentWidth() - 12);
  200. auto y = 0;
  201. y += group.updateSize (12, y, width - 12);
  202. y = jmax (comp.getParentHeight(), y);
  203. comp.setSize (width, y);
  204. }
  205. private:
  206. };