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.

277 lines
8.7KB

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