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.

331 lines
12KB

  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. #pragma once
  20. //==============================================================================
  21. class ModulesInformationComponent : public Component,
  22. private ListBoxModel,
  23. private ValueTree::Listener
  24. {
  25. public:
  26. ModulesInformationComponent (Project& p)
  27. : project (p),
  28. modulesValueTree (p.getModules().state)
  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. setCopyModeButton.setTriggeredOnMouseDown (true);
  42. setCopyModeButton.onClick = [this] { showCopyModeMenu(); };
  43. addAndMakeVisible (copyPathButton);
  44. copyPathButton.setTriggeredOnMouseDown (true);
  45. copyPathButton.onClick = [this] { showSetPathsMenu(); };
  46. addAndMakeVisible (globalPathsButton);
  47. globalPathsButton.onClick = [this] { showGlobalPathsMenu(); };
  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. buttonRow.removeFromLeft (8);
  73. globalPathsButton.setBounds (buttonRow.removeFromLeft (jmin (200, bounds.getWidth() / 3)));
  74. }
  75. }
  76. void parentSizeChanged() override
  77. {
  78. auto width = jmax (550, getParentWidth());
  79. auto y = list.getRowPosition (getNumRows() - 1, true).getBottom() + 200;
  80. y = jmax (getParentHeight(), y);
  81. setSize (width, y);
  82. }
  83. int getNumRows() override
  84. {
  85. return project.getModules().getNumModules();
  86. }
  87. void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) override
  88. {
  89. ignoreUnused (height);
  90. Rectangle<int> bounds (0, 0, width, height);
  91. g.setColour (rowIsSelected ? findColour (defaultHighlightColourId) : findColour (rowNumber % 2 == 0 ? widgetBackgroundColourId
  92. : secondaryWidgetBackgroundColourId));
  93. g.fillRect (bounds.withTrimmedBottom (1));
  94. bounds.removeFromLeft (5);
  95. g.setColour (rowIsSelected ? findColour (defaultHighlightedTextColourId) : findColour (widgetTextColourId));
  96. //======================================================================
  97. auto moduleID = project.getModules().getModuleID (rowNumber);
  98. g.drawFittedText (moduleID, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (0) * width)), Justification::centredLeft, 1);
  99. //======================================================================
  100. auto version = project.getModules().getModuleInfo (moduleID).getVersion();
  101. if (version.isEmpty())
  102. version = "?";
  103. g.drawFittedText (version, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (1) * width)), Justification::centredLeft, 1);
  104. //======================================================================
  105. auto copyLocally = project.getModules().shouldCopyModuleFilesLocally (moduleID).getValue() ? "Yes" : "No";
  106. g.drawFittedText (copyLocally, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (2) * width)), Justification::centredLeft, 1);
  107. //======================================================================
  108. String pathText;
  109. if (project.getModules().shouldUseGlobalPath (moduleID))
  110. {
  111. pathText = "Global";
  112. }
  113. else
  114. {
  115. StringArray paths;
  116. for (Project::ExporterIterator exporter (project); exporter.next();)
  117. paths.addIfNotAlreadyThere (exporter->getPathForModuleString (moduleID).trim());
  118. pathText = paths.joinIntoString (", ");
  119. }
  120. g.drawFittedText (pathText, bounds.removeFromLeft (roundToInt (listHeader->getProportionAtIndex (3) * width)), Justification::centredLeft, 1);
  121. }
  122. void listBoxItemDoubleClicked (int row, const MouseEvent&) override
  123. {
  124. auto moduleID = project.getModules().getModuleID (row);
  125. if (moduleID.isNotEmpty())
  126. if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>())
  127. pcc->showModule (moduleID);
  128. }
  129. void deleteKeyPressed (int row) override
  130. {
  131. project.getModules().removeModule (project.getModules().getModuleID (row));
  132. }
  133. void lookAndFeelChanged() override
  134. {
  135. setCopyModeButton.setColour (TextButton::buttonColourId, findColour (secondaryButtonBackgroundColourId));
  136. copyPathButton.setColour (TextButton::buttonColourId, findColour (defaultButtonBackgroundColourId));
  137. globalPathsButton.setColour (TextButton::buttonColourId, findColour (defaultButtonBackgroundColourId));
  138. }
  139. private:
  140. enum
  141. {
  142. nameCol = 1,
  143. versionCol,
  144. copyCol,
  145. pathCol
  146. };
  147. Project& project;
  148. ValueTree modulesValueTree;
  149. ContentViewHeader header { "Modules", { getIcons().modules, Colours::transparentBlack } };
  150. ListBox list;
  151. ListBoxHeader* listHeader;
  152. TextButton setCopyModeButton { "Set copy-mode for all modules..." };
  153. TextButton copyPathButton { "Set paths for all modules..." };
  154. TextButton globalPathsButton { "Enable/disable global path for modules..." };
  155. std::map<String, var> modulePathClipboard;
  156. void valueTreePropertyChanged (ValueTree&, const Identifier&) override { itemChanged(); }
  157. void valueTreeChildAdded (ValueTree&, ValueTree&) override { itemChanged(); }
  158. void valueTreeChildRemoved (ValueTree&, ValueTree&, int) override { itemChanged(); }
  159. void valueTreeChildOrderChanged (ValueTree&, int, int) override { itemChanged(); }
  160. void valueTreeParentChanged (ValueTree&) override { itemChanged(); }
  161. void itemChanged()
  162. {
  163. list.updateContent();
  164. resized();
  165. repaint();
  166. }
  167. void showCopyModeMenu()
  168. {
  169. PopupMenu m;
  170. m.addItem (1, "Set all modules to copy locally");
  171. m.addItem (2, "Set all modules to not copy locally");
  172. auto res = m.showAt (&setCopyModeButton);
  173. if (res != 0)
  174. project.getModules().setLocalCopyModeForAllModules (res == 1);
  175. }
  176. void showGlobalPathsMenu()
  177. {
  178. auto areAnyModulesSelected = (list.getNumSelectedRows() > 0);
  179. PopupMenu m;
  180. m.addItem (1, "Set all modules to use global paths");
  181. m.addItem (2, "Set all modules to not use global paths");
  182. m.addItem (3, "Set selected modules to use global paths", areAnyModulesSelected);
  183. m.addItem (4, "Set selected modules to not use global paths", areAnyModulesSelected);
  184. auto res = m.showAt (&globalPathsButton);
  185. if (res != 0)
  186. {
  187. auto enableGlobalPaths = (res % 2 == 1);
  188. auto& moduleList = project.getModules();
  189. if (res < 3)
  190. {
  191. auto moduleIDs = moduleList.getAllModules();
  192. for (auto id : moduleIDs)
  193. moduleList.getShouldUseGlobalPathValue (id).setValue (enableGlobalPaths);
  194. }
  195. else
  196. {
  197. auto selected = list.getSelectedRows();
  198. for (int i = 0; i < selected.size(); ++i)
  199. moduleList.getShouldUseGlobalPathValue (moduleList.getModuleID (selected[i])).setValue (enableGlobalPaths);
  200. }
  201. }
  202. }
  203. void showSetPathsMenu()
  204. {
  205. enum
  206. {
  207. copyPathsToAllModulesID = 1,
  208. copyPathsID,
  209. pastePathsID
  210. };
  211. auto& moduleList = project.getModules();
  212. auto moduleToCopy = moduleList.getModuleID (list.getSelectedRow());
  213. if (moduleToCopy.isNotEmpty())
  214. {
  215. PopupMenu m;
  216. m.addItem (copyPathsToAllModulesID, "Copy the paths from the module '" + moduleToCopy + "' to all other modules");
  217. m.addItem (copyPathsID, "Copy paths from selected module", list.getNumSelectedRows() == 1);
  218. m.addItem (pastePathsID, "Paste paths to selected modules", ! modulePathClipboard.empty());
  219. int res = m.showAt (&copyPathButton);
  220. if (res == copyPathsToAllModulesID)
  221. {
  222. for (Project::ExporterIterator exporter (project); exporter.next();)
  223. {
  224. for (int i = 0; i < moduleList.getNumModules(); ++i)
  225. {
  226. auto modID = moduleList.getModuleID (i);
  227. if (modID != moduleToCopy)
  228. exporter->getPathForModuleValue (modID) = exporter->getPathForModuleValue (moduleToCopy).getValue();
  229. }
  230. }
  231. }
  232. else if (res == copyPathsID)
  233. {
  234. modulePathClipboard.clear();
  235. for (Project::ExporterIterator exporter (project); exporter.next();)
  236. modulePathClipboard[exporter->getName()] = exporter->getPathForModuleValue (moduleToCopy).getValue();
  237. }
  238. else if (res == pastePathsID)
  239. {
  240. for (int selectionId = 0; selectionId < list.getNumSelectedRows(); ++selectionId)
  241. {
  242. auto rowNumber = list.getSelectedRow (selectionId);
  243. auto modID = moduleList.getModuleID (rowNumber);
  244. for (Project::ExporterIterator exporter (project); exporter.next();)
  245. exporter->getPathForModuleValue (modID) = modulePathClipboard[exporter->getName()];
  246. }
  247. }
  248. list.repaint();
  249. }
  250. else
  251. {
  252. PopupMenu m;
  253. m.addItem (1, "(Select a module in the list above to use this option)", false);
  254. m.showAt (&copyPathButton);
  255. }
  256. }
  257. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModulesInformationComponent)
  258. };