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.

268 lines
10KB

  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. class ModulesPanel : public Component,
  18. private ListBoxModel,
  19. private ValueTree::Listener,
  20. private Button::Listener
  21. {
  22. public:
  23. ModulesPanel (Project& p)
  24. : project (p),
  25. modulesValueTree (p.getModules().state),
  26. header ("Modules", Icon (getIcons().modules, Colours::transparentBlack)),
  27. setCopyModeButton ("Set copy-mode for all modules..."),
  28. copyPathButton ("Set paths for all modules...")
  29. {
  30. listHeader = new ListBoxHeader ( { "Module", "Version", "Make Local Copy", "Paths" },
  31. { 0.25f, 0.2f, 0.2f, 0.35f } );
  32. list.setHeaderComponent (listHeader);
  33. list.setModel (this);
  34. list.setColour (ListBox::backgroundColourId, Colours::transparentBlack);
  35. addAndMakeVisible (list);
  36. list.updateContent();
  37. list.setRowHeight (30);
  38. list.setMultipleSelectionEnabled (true);
  39. addAndMakeVisible (header);
  40. addAndMakeVisible (setCopyModeButton);
  41. addAndMakeVisible (copyPathButton);
  42. setCopyModeButton.addListener (this);
  43. setCopyModeButton.setTriggeredOnMouseDown (true);
  44. copyPathButton.addListener (this);
  45. copyPathButton.setTriggeredOnMouseDown (true);
  46. modulesValueTree.addListener (this);
  47. lookAndFeelChanged();
  48. }
  49. void paint (Graphics& g) override
  50. {
  51. g.setColour (findColour (secondaryBackgroundColourId));
  52. g.fillRect (getLocalBounds().reduced (12, 0));
  53. }
  54. void resized() override
  55. {
  56. auto bounds = getLocalBounds().reduced (12, 0);
  57. header.setBounds (bounds.removeFromTop (40));
  58. bounds.reduce (10, 0);
  59. list.setBounds (bounds.removeFromTop (list.getRowPosition (getNumRows() - 1, true).getBottom() + 20));
  60. auto buttonRow = bounds.removeFromTop (35);
  61. setCopyModeButton.setBounds (buttonRow.removeFromLeft (jmin (200, bounds.getWidth() / 3)));
  62. buttonRow.removeFromLeft (8);
  63. copyPathButton.setBounds (buttonRow.removeFromLeft (jmin (200, bounds.getWidth() / 3)));
  64. }
  65. void parentSizeChanged() override
  66. {
  67. setSize (jmax (550, getParentWidth()), getParentHeight());
  68. }
  69. int getNumRows() override
  70. {
  71. return project.getModules().getNumModules();
  72. }
  73. void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) override
  74. {
  75. ignoreUnused (height);
  76. auto bounds = Rectangle<int> (0, 0, width, height);
  77. g.setColour (rowIsSelected ? findColour (defaultHighlightColourId) : findColour (rowNumber % 2 == 0 ? widgetBackgroundColourId
  78. : secondaryWidgetBackgroundColourId));
  79. g.fillRect (bounds.withTrimmedBottom (1));
  80. bounds.removeFromLeft (5);
  81. g.setColour (rowIsSelected ? findColour (defaultHighlightedTextColourId) : findColour (widgetTextColourId));
  82. //======================================================================
  83. const auto moduleID = project.getModules().getModuleID (rowNumber);
  84. g.drawFittedText (moduleID, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (0) * width)), Justification::centredLeft, 1);
  85. //======================================================================
  86. auto version = project.getModules().getModuleInfo (moduleID).getVersion();
  87. if (version.isEmpty())
  88. version = "?";
  89. g.drawFittedText (version, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (1) * width)), Justification::centredLeft, 1);
  90. //======================================================================
  91. const auto copyLocally = project.getModules().shouldCopyModuleFilesLocally (moduleID).getValue()
  92. ? "Yes" : "No";
  93. g.drawFittedText (copyLocally, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (2) * width)), Justification::centredLeft, 1);
  94. //======================================================================
  95. StringArray paths;
  96. for (Project::ExporterIterator exporter (project); exporter.next();)
  97. paths.addIfNotAlreadyThere (exporter->getPathForModuleString (moduleID).trim());
  98. const auto pathText = paths.joinIntoString (", ");
  99. g.drawFittedText (pathText, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (3) * width)), Justification::centredLeft, 1);
  100. }
  101. void listBoxItemDoubleClicked (int row, const MouseEvent&) override
  102. {
  103. const String moduleID (project.getModules().getModuleID (row));
  104. if (moduleID.isNotEmpty())
  105. if (ProjectContentComponent* pcc = findParentComponentOfClass<ProjectContentComponent>())
  106. pcc->showModule (moduleID);
  107. }
  108. void deleteKeyPressed (int row) override
  109. {
  110. project.getModules().removeModule (project.getModules().getModuleID (row));
  111. }
  112. void buttonClicked (Button* b) override
  113. {
  114. if (b == &setCopyModeButton) showCopyModeMenu();
  115. if (b == &copyPathButton) showSetPathsMenu();
  116. }
  117. void lookAndFeelChanged() override
  118. {
  119. setCopyModeButton.setColour (TextButton::buttonColourId, findColour (secondaryButtonBackgroundColourId));
  120. copyPathButton.setColour (TextButton::buttonColourId, findColour (defaultButtonBackgroundColourId));
  121. }
  122. private:
  123. enum
  124. {
  125. nameCol = 1,
  126. versionCol,
  127. copyCol,
  128. pathCol
  129. };
  130. Project& project;
  131. ValueTree modulesValueTree;
  132. ContentViewHeader header;
  133. ListBox list;
  134. ListBoxHeader* listHeader;
  135. TextButton setCopyModeButton, copyPathButton;
  136. std::map<String, var> modulePathClipboard;
  137. void valueTreePropertyChanged (ValueTree&, const Identifier&) override { itemChanged(); }
  138. void valueTreeChildAdded (ValueTree&, ValueTree&) override { itemChanged(); }
  139. void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override { itemChanged(); }
  140. void valueTreeChildOrderChanged (ValueTree&, int, int) override { itemChanged(); }
  141. void valueTreeParentChanged (ValueTree&) override { itemChanged(); }
  142. void itemChanged()
  143. {
  144. list.updateContent();
  145. resized();
  146. repaint();
  147. }
  148. void showCopyModeMenu()
  149. {
  150. PopupMenu m;
  151. m.addItem (1, "Set all modules to copy locally");
  152. m.addItem (2, "Set all modules to not copy locally");
  153. int res = m.showAt (&setCopyModeButton);
  154. if (res != 0)
  155. project.getModules().setLocalCopyModeForAllModules (res == 1);
  156. }
  157. void showSetPathsMenu()
  158. {
  159. enum
  160. {
  161. copyPathsToAllModulesID = 1,
  162. copyPathsID,
  163. pastePathsID
  164. };
  165. auto& moduleList = project.getModules();
  166. auto moduleToCopy = moduleList.getModuleID (list.getSelectedRow());
  167. if (moduleToCopy.isNotEmpty())
  168. {
  169. PopupMenu m;
  170. m.addItem (copyPathsToAllModulesID, "Copy the paths from the module '" + moduleToCopy + "' to all other modules");
  171. m.addItem (copyPathsID, "Copy paths from selected module", list.getNumSelectedRows() == 1);
  172. m.addItem (pastePathsID, "Paste paths to selected modules", ! modulePathClipboard.empty());
  173. int res = m.showAt (&copyPathButton);
  174. if (res == copyPathsToAllModulesID)
  175. {
  176. for (Project::ExporterIterator exporter (project); exporter.next();)
  177. {
  178. for (int i = 0; i < moduleList.getNumModules(); ++i)
  179. {
  180. auto modID = moduleList.getModuleID (i);
  181. if (modID != moduleToCopy)
  182. exporter->getPathForModuleValue (modID) = exporter->getPathForModuleValue (moduleToCopy).getValue();
  183. }
  184. }
  185. }
  186. else if (res == copyPathsID)
  187. {
  188. modulePathClipboard.clear();
  189. for (Project::ExporterIterator exporter (project); exporter.next();)
  190. modulePathClipboard[exporter->getName()] = exporter->getPathForModuleValue (moduleToCopy).getValue();
  191. }
  192. else if (res == pastePathsID)
  193. {
  194. for (int selectionId = 0; selectionId < list.getNumSelectedRows(); ++selectionId)
  195. {
  196. auto rowNumber = list.getSelectedRow (selectionId);
  197. auto modID = moduleList.getModuleID (rowNumber);
  198. for (Project::ExporterIterator exporter (project); exporter.next();)
  199. exporter->getPathForModuleValue (modID) = modulePathClipboard[exporter->getName()];
  200. }
  201. }
  202. list.repaint();
  203. }
  204. else
  205. {
  206. PopupMenu m;
  207. m.addItem (1, "(Select a module in the list above to use this option)", false);
  208. m.showAt (&copyPathButton);
  209. }
  210. }
  211. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModulesPanel)
  212. };