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.

270 lines
8.3KB

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