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.

273 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 (pp->getName() == "Dependencies")
  146. return;
  147. if (auto* propertyChild = pp->getChildComponent (0))
  148. {
  149. auto bounds = propertyChild->getBounds();
  150. propertyChild->setBounds (bounds.withSizeKeepingCentre (propertyChild->getWidth(), pp->getPreferredHeight()));
  151. }
  152. }
  153. OwnedArray<PropertyComponent> properties;
  154. OwnedArray<InfoButton> infoButtons;
  155. ContentViewHeader header;
  156. private:
  157. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertyGroupComponent)
  158. };
  159. //==============================================================================
  160. class ConfigTreeItemBase : public JucerTreeViewBase,
  161. public ValueTree::Listener
  162. {
  163. public:
  164. ConfigTreeItemBase() {}
  165. void showSettingsPage (Component* content)
  166. {
  167. content->setComponentID (getUniqueName());
  168. ScopedPointer<Component> comp (content);
  169. if (ProjectContentComponent* pcc = getProjectContentComponent())
  170. pcc->setEditorComponent (comp.release(), nullptr);
  171. }
  172. void closeSettingsPage()
  173. {
  174. if (auto* pcc = getProjectContentComponent())
  175. {
  176. if (auto* content = dynamic_cast<Viewport*> (pcc->getEditorComponent()->getChildComponent (0)))
  177. if (content->getViewedComponent()->getComponentID() == getUniqueName())
  178. pcc->hideEditor();
  179. }
  180. }
  181. void deleteAllSelectedItems() override
  182. {
  183. TreeView* const tree = getOwnerView();
  184. jassert (tree->getNumSelectedItems() <= 1); // multi-select should be disabled
  185. if (ConfigTreeItemBase* s = dynamic_cast<ConfigTreeItemBase*> (tree->getSelectedItem (0)))
  186. s->deleteItem();
  187. }
  188. void itemOpennessChanged (bool isNowOpen) override
  189. {
  190. if (isNowOpen)
  191. refreshSubItems();
  192. }
  193. void valueTreePropertyChanged (ValueTree&, const Identifier&) override {}
  194. void valueTreeChildAdded (ValueTree&, ValueTree&) override {}
  195. void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override {}
  196. void valueTreeChildOrderChanged (ValueTree&, int, int) override {}
  197. void valueTreeParentChanged (ValueTree&) override {}
  198. virtual bool isProjectSettings() const { return false; }
  199. virtual bool isModulesList() const { return false; }
  200. static void updateSize (Component& comp, PropertyGroupComponent& group)
  201. {
  202. const auto width = jmax (550, comp.getParentWidth() - 12);
  203. auto y = 0;
  204. y += group.updateSize (12, y, width - 12);
  205. y = jmax (comp.getParentHeight(), y);
  206. comp.setSize (width, y);
  207. }
  208. private:
  209. };