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
10KB

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