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.

308 lines
9.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  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 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. #pragma once
  19. //==============================================================================
  20. struct ProjectSettingsComponent : public Component,
  21. private ChangeListener
  22. {
  23. ProjectSettingsComponent (Project& p)
  24. : project (p),
  25. group (project.getProjectFilenameRootString(),
  26. Icon (getIcons().settings, Colours::transparentBlack))
  27. {
  28. setTitle ("Project Settings");
  29. setFocusContainerType (FocusContainerType::focusContainer);
  30. addAndMakeVisible (group);
  31. updatePropertyList();
  32. project.addChangeListener (this);
  33. }
  34. ~ProjectSettingsComponent() override
  35. {
  36. project.removeChangeListener (this);
  37. }
  38. void resized() override
  39. {
  40. group.updateSize (12, 0, getWidth() - 24);
  41. group.setBounds (getLocalBounds().reduced (12, 0));
  42. }
  43. void updatePropertyList()
  44. {
  45. PropertyListBuilder props;
  46. project.createPropertyEditors (props);
  47. group.setProperties (props);
  48. group.setName ("Project Settings");
  49. lastProjectType = project.getProjectTypeString();
  50. parentSizeChanged();
  51. }
  52. void changeListenerCallback (ChangeBroadcaster*) override
  53. {
  54. if (lastProjectType != project.getProjectTypeString())
  55. updatePropertyList();
  56. }
  57. void parentSizeChanged() override
  58. {
  59. auto width = jmax (550, getParentWidth());
  60. auto y = group.updateSize (12, 0, width - 12);
  61. y = jmax (getParentHeight(), y);
  62. setSize (width, y);
  63. }
  64. Project& project;
  65. var lastProjectType;
  66. PropertyGroupComponent group;
  67. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectSettingsComponent)
  68. };
  69. //==============================================================================
  70. struct FileTreePanel : public TreePanelBase
  71. {
  72. FileTreePanel (Project& p)
  73. : TreePanelBase (&p, "fileTreeState")
  74. {
  75. tree.setMultiSelectEnabled (true);
  76. setRoot (new TreeItemTypes::GroupItem (p.getMainGroup()));
  77. tree.setRootItemVisible (false);
  78. }
  79. void updateMissingFileStatuses()
  80. {
  81. if (auto* p = dynamic_cast<TreeItemTypes::FileTreeItemBase*> (rootItem.get()))
  82. p->checkFileStatus();
  83. }
  84. };
  85. struct ModuleTreePanel : public TreePanelBase
  86. {
  87. ModuleTreePanel (Project& p)
  88. : TreePanelBase (&p, "moduleTreeState")
  89. {
  90. tree.setMultiSelectEnabled (false);
  91. setRoot (new TreeItemTypes::EnabledModulesItem (p));
  92. tree.setRootItemVisible (false);
  93. }
  94. };
  95. struct ExportersTreePanel : public TreePanelBase
  96. {
  97. ExportersTreePanel (Project& p)
  98. : TreePanelBase (&p, "exportersTreeState")
  99. {
  100. tree.setMultiSelectEnabled (false);
  101. setRoot (new TreeItemTypes::ExportersTreeRoot (p));
  102. tree.setRootItemVisible (false);
  103. }
  104. };
  105. //==============================================================================
  106. class ProjectTab : public Component,
  107. private ChangeListener
  108. {
  109. public:
  110. ProjectTab (Project* p)
  111. : project (p)
  112. {
  113. addAndMakeVisible (concertinaPanel);
  114. buildConcertina();
  115. }
  116. ~ProjectTab() override
  117. {
  118. getFileTreePanel()->saveOpenness();
  119. getModuleTreePanel()->saveOpenness();
  120. getExportersTreePanel()->saveOpenness();
  121. }
  122. void paint (Graphics& g) override
  123. {
  124. g.fillAll (findColour (secondaryBackgroundColourId));
  125. }
  126. void resized() override
  127. {
  128. concertinaPanel.setBounds (getLocalBounds().withTrimmedBottom (3));
  129. }
  130. TreePanelBase* getTreeWithSelectedItems()
  131. {
  132. for (auto i = concertinaPanel.getNumPanels() - 1; i >= 0; --i)
  133. {
  134. if (auto* treeComponent = dynamic_cast<ConcertinaTreeComponent*> (concertinaPanel.getPanel (i)))
  135. {
  136. if (auto* base = treeComponent->getTree())
  137. if (base->tree.getNumSelectedItems() != 0)
  138. return base;
  139. }
  140. }
  141. return nullptr;
  142. }
  143. FileTreePanel* getFileTreePanel()
  144. {
  145. if (auto* panel = dynamic_cast<ConcertinaTreeComponent*> (concertinaPanel.getPanel (0)))
  146. return dynamic_cast<FileTreePanel*> (panel->getTree());
  147. return nullptr;
  148. }
  149. ModuleTreePanel* getModuleTreePanel()
  150. {
  151. if (auto* panel = dynamic_cast<ConcertinaTreeComponent*> (concertinaPanel.getPanel (1)))
  152. return dynamic_cast<ModuleTreePanel*> (panel->getTree());
  153. return nullptr;
  154. }
  155. ExportersTreePanel* getExportersTreePanel()
  156. {
  157. if (auto* panel = dynamic_cast<ConcertinaTreeComponent*> (concertinaPanel.getPanel (2)))
  158. return dynamic_cast<ExportersTreePanel*> (panel->getTree());
  159. return nullptr;
  160. }
  161. void showPanel (int panelIndex)
  162. {
  163. jassert (isPositiveAndBelow (panelIndex, concertinaPanel.getNumPanels()));
  164. concertinaPanel.expandPanelFully (concertinaPanel.getPanel (panelIndex), true);
  165. }
  166. void setPanelHeightProportion (int panelIndex, float prop)
  167. {
  168. jassert (isPositiveAndBelow (panelIndex, concertinaPanel.getNumPanels()));
  169. concertinaPanel.setPanelSize (concertinaPanel.getPanel (panelIndex),
  170. roundToInt (prop * (float) (concertinaPanel.getHeight() - 90)), false);
  171. }
  172. float getPanelHeightProportion (int panelIndex)
  173. {
  174. jassert (isPositiveAndBelow (panelIndex, concertinaPanel.getNumPanels()));
  175. return ((float) (concertinaPanel.getPanel (panelIndex)->getHeight()) / (float) (concertinaPanel.getHeight() - 90));
  176. }
  177. private:
  178. ConcertinaPanel concertinaPanel;
  179. OwnedArray<ConcertinaHeader> headers;
  180. Project* project = nullptr;
  181. //==============================================================================
  182. void changeListenerCallback (ChangeBroadcaster* source) override
  183. {
  184. if (auto* header = dynamic_cast<ConcertinaHeader*> (source))
  185. {
  186. auto index = headers.indexOf (header);
  187. concertinaPanel.expandPanelFully (concertinaPanel.getPanel (index), true);
  188. }
  189. }
  190. void buildConcertina()
  191. {
  192. for (auto i = concertinaPanel.getNumPanels() - 1; i >= 0 ; --i)
  193. concertinaPanel.removePanel (concertinaPanel.getPanel (i));
  194. headers.clear();
  195. auto addPanel = [this] (const String& name,
  196. TreePanelBase* tree,
  197. ConcertinaTreeComponent::AdditionalComponents components,
  198. const Path& icon)
  199. {
  200. if (project != nullptr)
  201. concertinaPanel.addPanel (-1, new ConcertinaTreeComponent (name, tree, components), true);
  202. headers.add (new ConcertinaHeader (name, icon));
  203. };
  204. using AdditionalComponents = ConcertinaTreeComponent::AdditionalComponents;
  205. addPanel ("File Explorer", new FileTreePanel (*project),
  206. AdditionalComponents{}
  207. .with (AdditionalComponents::addButton)
  208. .with (AdditionalComponents::findPanel),
  209. getIcons().fileExplorer);
  210. addPanel ("Modules", new ModuleTreePanel (*project),
  211. AdditionalComponents{}
  212. .with (AdditionalComponents::addButton)
  213. .with (AdditionalComponents::settingsButton),
  214. getIcons().modules);
  215. addPanel ("Exporters", new ExportersTreePanel (*project),
  216. AdditionalComponents{}.with (AdditionalComponents::addButton),
  217. getIcons().exporter);
  218. for (int i = 0; i < concertinaPanel.getNumPanels(); ++i)
  219. {
  220. auto* p = concertinaPanel.getPanel (i);
  221. auto* h = headers.getUnchecked (i);
  222. p->addMouseListener (this, true);
  223. h->addChangeListener (this);
  224. h->yPosition = i * 30;
  225. concertinaPanel.setCustomPanelHeader (p, h, false);
  226. concertinaPanel.setPanelHeaderSize (p, 30);
  227. }
  228. }
  229. void mouseDown (const MouseEvent& e) override
  230. {
  231. for (auto i = concertinaPanel.getNumPanels() - 1; i >= 0; --i)
  232. {
  233. auto* p = concertinaPanel.getPanel (i);
  234. if (! (p->isParentOf (e.eventComponent)))
  235. {
  236. auto* base = dynamic_cast<TreePanelBase*> (p);
  237. if (base == nullptr)
  238. base = dynamic_cast<ConcertinaTreeComponent*> (p)->getTree();
  239. if (base != nullptr)
  240. base->tree.clearSelectedItems();
  241. }
  242. }
  243. }
  244. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProjectTab)
  245. };