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.

337 lines
13KB

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