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.

282 lines
11KB

  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. if (bounds.getHeight() < 35)
  63. {
  64. parentSizeChanged();
  65. }
  66. else
  67. {
  68. auto buttonRow = bounds.removeFromTop (35);
  69. setCopyModeButton.setBounds (buttonRow.removeFromLeft (jmin (200, bounds.getWidth() / 3)));
  70. buttonRow.removeFromLeft (8);
  71. copyPathButton.setBounds (buttonRow.removeFromLeft (jmin (200, bounds.getWidth() / 3)));
  72. }
  73. }
  74. void parentSizeChanged() override
  75. {
  76. const auto width = jmax (550, getParentWidth());
  77. auto y = list.getRowPosition (getNumRows() - 1, true).getBottom() + 100;
  78. y = jmax (getParentHeight(), y);
  79. setSize (width, y);
  80. }
  81. int getNumRows() override
  82. {
  83. return project.getModules().getNumModules();
  84. }
  85. void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) override
  86. {
  87. ignoreUnused (height);
  88. auto bounds = Rectangle<int> (0, 0, width, height);
  89. g.setColour (rowIsSelected ? findColour (defaultHighlightColourId) : findColour (rowNumber % 2 == 0 ? widgetBackgroundColourId
  90. : secondaryWidgetBackgroundColourId));
  91. g.fillRect (bounds.withTrimmedBottom (1));
  92. bounds.removeFromLeft (5);
  93. g.setColour (rowIsSelected ? findColour (defaultHighlightedTextColourId) : findColour (widgetTextColourId));
  94. //======================================================================
  95. const auto moduleID = project.getModules().getModuleID (rowNumber);
  96. g.drawFittedText (moduleID, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (0) * width)), Justification::centredLeft, 1);
  97. //======================================================================
  98. auto version = project.getModules().getModuleInfo (moduleID).getVersion();
  99. if (version.isEmpty())
  100. version = "?";
  101. g.drawFittedText (version, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (1) * width)), Justification::centredLeft, 1);
  102. //======================================================================
  103. const auto copyLocally = project.getModules().shouldCopyModuleFilesLocally (moduleID).getValue()
  104. ? "Yes" : "No";
  105. g.drawFittedText (copyLocally, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (2) * width)), Justification::centredLeft, 1);
  106. //======================================================================
  107. StringArray paths;
  108. for (Project::ExporterIterator exporter (project); exporter.next();)
  109. paths.addIfNotAlreadyThere (exporter->getPathForModuleString (moduleID).trim());
  110. const auto pathText = paths.joinIntoString (", ");
  111. g.drawFittedText (pathText, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (3) * width)), Justification::centredLeft, 1);
  112. }
  113. void listBoxItemDoubleClicked (int row, const MouseEvent&) override
  114. {
  115. const String moduleID (project.getModules().getModuleID (row));
  116. if (moduleID.isNotEmpty())
  117. if (ProjectContentComponent* pcc = findParentComponentOfClass<ProjectContentComponent>())
  118. pcc->showModule (moduleID);
  119. }
  120. void deleteKeyPressed (int row) override
  121. {
  122. project.getModules().removeModule (project.getModules().getModuleID (row));
  123. }
  124. void buttonClicked (Button* b) override
  125. {
  126. if (b == &setCopyModeButton) showCopyModeMenu();
  127. if (b == &copyPathButton) showSetPathsMenu();
  128. }
  129. void lookAndFeelChanged() override
  130. {
  131. setCopyModeButton.setColour (TextButton::buttonColourId, findColour (secondaryButtonBackgroundColourId));
  132. copyPathButton.setColour (TextButton::buttonColourId, findColour (defaultButtonBackgroundColourId));
  133. }
  134. private:
  135. enum
  136. {
  137. nameCol = 1,
  138. versionCol,
  139. copyCol,
  140. pathCol
  141. };
  142. Project& project;
  143. ValueTree modulesValueTree;
  144. ContentViewHeader header;
  145. ListBox list;
  146. ListBoxHeader* listHeader;
  147. TextButton setCopyModeButton, copyPathButton;
  148. std::map<String, var> modulePathClipboard;
  149. void valueTreePropertyChanged (ValueTree&, const Identifier&) override { itemChanged(); }
  150. void valueTreeChildAdded (ValueTree&, ValueTree&) override { itemChanged(); }
  151. void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override { itemChanged(); }
  152. void valueTreeChildOrderChanged (ValueTree&, int, int) override { itemChanged(); }
  153. void valueTreeParentChanged (ValueTree&) override { itemChanged(); }
  154. void itemChanged()
  155. {
  156. list.updateContent();
  157. resized();
  158. repaint();
  159. }
  160. void showCopyModeMenu()
  161. {
  162. PopupMenu m;
  163. m.addItem (1, "Set all modules to copy locally");
  164. m.addItem (2, "Set all modules to not copy locally");
  165. int res = m.showAt (&setCopyModeButton);
  166. if (res != 0)
  167. project.getModules().setLocalCopyModeForAllModules (res == 1);
  168. }
  169. void showSetPathsMenu()
  170. {
  171. enum
  172. {
  173. copyPathsToAllModulesID = 1,
  174. copyPathsID,
  175. pastePathsID
  176. };
  177. auto& moduleList = project.getModules();
  178. auto moduleToCopy = moduleList.getModuleID (list.getSelectedRow());
  179. if (moduleToCopy.isNotEmpty())
  180. {
  181. PopupMenu m;
  182. m.addItem (copyPathsToAllModulesID, "Copy the paths from the module '" + moduleToCopy + "' to all other modules");
  183. m.addItem (copyPathsID, "Copy paths from selected module", list.getNumSelectedRows() == 1);
  184. m.addItem (pastePathsID, "Paste paths to selected modules", ! modulePathClipboard.empty());
  185. int res = m.showAt (&copyPathButton);
  186. if (res == copyPathsToAllModulesID)
  187. {
  188. for (Project::ExporterIterator exporter (project); exporter.next();)
  189. {
  190. for (int i = 0; i < moduleList.getNumModules(); ++i)
  191. {
  192. auto modID = moduleList.getModuleID (i);
  193. if (modID != moduleToCopy)
  194. exporter->getPathForModuleValue (modID) = exporter->getPathForModuleValue (moduleToCopy).getValue();
  195. }
  196. }
  197. }
  198. else if (res == copyPathsID)
  199. {
  200. modulePathClipboard.clear();
  201. for (Project::ExporterIterator exporter (project); exporter.next();)
  202. modulePathClipboard[exporter->getName()] = exporter->getPathForModuleValue (moduleToCopy).getValue();
  203. }
  204. else if (res == pastePathsID)
  205. {
  206. for (int selectionId = 0; selectionId < list.getNumSelectedRows(); ++selectionId)
  207. {
  208. auto rowNumber = list.getSelectedRow (selectionId);
  209. auto modID = moduleList.getModuleID (rowNumber);
  210. for (Project::ExporterIterator exporter (project); exporter.next();)
  211. exporter->getPathForModuleValue (modID) = modulePathClipboard[exporter->getName()];
  212. }
  213. }
  214. list.repaint();
  215. }
  216. else
  217. {
  218. PopupMenu m;
  219. m.addItem (1, "(Select a module in the list above to use this option)", false);
  220. m.showAt (&copyPathButton);
  221. }
  222. }
  223. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModulesPanel)
  224. };