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.

327 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  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 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. #pragma once
  19. #include "../../ProjectSaving/jucer_ProjectExporter.h"
  20. #include "../../Utility/UI/PropertyComponents/jucer_FilePathPropertyComponent.h"
  21. #include "../../Utility/Helpers/jucer_ValueTreePropertyWithDefaultWrapper.h"
  22. #include "jucer_NewProjectWizard.h"
  23. //==============================================================================
  24. class ItemHeader : public Component
  25. {
  26. public:
  27. ItemHeader (StringRef name, StringRef description, const char* iconSvgData)
  28. : nameLabel ({}, name),
  29. descriptionLabel ({}, description),
  30. icon (makeIcon (iconSvgData))
  31. {
  32. addAndMakeVisible (nameLabel);
  33. nameLabel.setFont (18.0f);
  34. nameLabel.setMinimumHorizontalScale (1.0f);
  35. addAndMakeVisible (descriptionLabel);
  36. descriptionLabel.setMinimumHorizontalScale (1.0f);
  37. }
  38. void resized() override
  39. {
  40. auto bounds = getLocalBounds();
  41. auto topSlice = bounds.removeFromTop (50);
  42. iconBounds = topSlice.removeFromRight (75);
  43. nameLabel.setBounds (topSlice);
  44. bounds.removeFromTop (10);
  45. descriptionLabel.setBounds (bounds.removeFromTop (50));
  46. bounds.removeFromTop (20);
  47. }
  48. void paint (Graphics& g) override
  49. {
  50. g.fillAll (findColour (secondaryBackgroundColourId));
  51. if (icon != nullptr)
  52. icon->drawWithin (g, iconBounds.toFloat(), RectanglePlacement::centred, 1.0f);
  53. }
  54. private:
  55. static std::unique_ptr<Drawable> makeIcon (const char* iconSvgData)
  56. {
  57. if (auto svg = XmlDocument::parse (iconSvgData))
  58. return Drawable::createFromSVG (*svg);
  59. return {};
  60. }
  61. Label nameLabel, descriptionLabel;
  62. Rectangle<int> iconBounds;
  63. std::unique_ptr<Drawable> icon;
  64. //==============================================================================
  65. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ItemHeader)
  66. };
  67. //==============================================================================
  68. class TemplateComponent : public Component
  69. {
  70. public:
  71. TemplateComponent (const NewProjectTemplates::ProjectTemplate& temp,
  72. std::function<void (std::unique_ptr<Project>)>&& createdCallback)
  73. : projectTemplate (temp),
  74. projectCreatedCallback (std::move (createdCallback)),
  75. header (projectTemplate.displayName, projectTemplate.description, projectTemplate.icon)
  76. {
  77. createProjectButton.onClick = [this]
  78. {
  79. chooser = std::make_unique<FileChooser> ("Save Project", NewProjectWizard::getLastWizardFolder());
  80. auto browserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories;
  81. chooser->launchAsync (browserFlags, [this] (const FileChooser& fc)
  82. {
  83. auto dir = fc.getResult();
  84. if (dir == File{})
  85. return;
  86. SafePointer<TemplateComponent> safeThis { this };
  87. NewProjectWizard::createNewProject (projectTemplate,
  88. dir.getChildFile (projectNameValue.get().toString()),
  89. projectNameValue.get(),
  90. modulesValue.get(),
  91. exportersValue.get(),
  92. fileOptionsValue.get(),
  93. modulePathValue.getCurrentValue(),
  94. modulePathValue.getWrappedValueTreePropertyWithDefault().isUsingDefault(),
  95. [safeThis, dir] (std::unique_ptr<Project> project)
  96. {
  97. if (safeThis == nullptr)
  98. return;
  99. safeThis->projectCreatedCallback (std::move (project));
  100. getAppSettings().lastWizardFolder = dir;
  101. });
  102. });
  103. };
  104. addAndMakeVisible (createProjectButton);
  105. addAndMakeVisible (header);
  106. modulePathValue.init ({ settingsTree, Ids::defaultJuceModulePath, nullptr },
  107. getAppSettings().getStoredPath (Ids::defaultJuceModulePath, TargetOS::getThisOS()),
  108. TargetOS::getThisOS());
  109. panel.addProperties (buildPropertyList(), 2);
  110. addAndMakeVisible (panel);
  111. }
  112. void resized() override
  113. {
  114. auto bounds = getLocalBounds().reduced (10);
  115. header.setBounds (bounds.removeFromTop (150));
  116. createProjectButton.setBounds (bounds.removeFromBottom (30).removeFromRight (150));
  117. bounds.removeFromBottom (5);
  118. panel.setBounds (bounds);
  119. }
  120. void paint (Graphics& g) override
  121. {
  122. g.fillAll (findColour (secondaryBackgroundColourId));
  123. }
  124. private:
  125. NewProjectTemplates::ProjectTemplate projectTemplate;
  126. std::unique_ptr<FileChooser> chooser;
  127. std::function<void (std::unique_ptr<Project>)> projectCreatedCallback;
  128. ItemHeader header;
  129. TextButton createProjectButton { "Create Project..." };
  130. ValueTree settingsTree { "NewProjectSettings" };
  131. ValueTreePropertyWithDefault projectNameValue { settingsTree, Ids::name, nullptr, "NewProject" },
  132. modulesValue { settingsTree, Ids::dependencies_, nullptr, projectTemplate.requiredModules, "," },
  133. exportersValue { settingsTree, Ids::exporters, nullptr, StringArray (ProjectExporter::getCurrentPlatformExporterTypeInfo().identifier.toString()), "," },
  134. fileOptionsValue { settingsTree, Ids::file, nullptr, NewProjectTemplates::getVarForFileOption (projectTemplate.defaultFileOption) };
  135. ValueTreePropertyWithDefaultWrapper modulePathValue;
  136. PropertyPanel panel;
  137. //==============================================================================
  138. PropertyComponent* createProjectNamePropertyComponent()
  139. {
  140. return new TextPropertyComponent (projectNameValue, "Project Name", 1024, false);
  141. }
  142. PropertyComponent* createModulesPropertyComponent()
  143. {
  144. Array<var> moduleVars;
  145. var requiredModules;
  146. for (auto& m : getJUCEModules())
  147. {
  148. moduleVars.add (m);
  149. if (projectTemplate.requiredModules.contains (m))
  150. requiredModules.append (m);
  151. }
  152. modulesValue = requiredModules;
  153. return new MultiChoicePropertyComponent (modulesValue, "Modules",
  154. getJUCEModules(), moduleVars);
  155. }
  156. PropertyComponent* createModulePathPropertyComponent()
  157. {
  158. return new FilePathPropertyComponent (modulePathValue.getWrappedValueTreePropertyWithDefault(), "Path to Modules", true);
  159. }
  160. PropertyComponent* createExportersPropertyValue()
  161. {
  162. Array<var> exporterVars;
  163. StringArray exporterNames;
  164. for (auto& exporterTypeInfo : ProjectExporter::getExporterTypeInfos())
  165. {
  166. exporterVars.add (exporterTypeInfo.identifier.toString());
  167. exporterNames.add (exporterTypeInfo.displayName);
  168. }
  169. return new MultiChoicePropertyComponent (exportersValue, "Exporters", exporterNames, exporterVars);
  170. }
  171. PropertyComponent* createFileCreationOptionsPropertyComponent()
  172. {
  173. Array<var> optionVars;
  174. StringArray optionStrings;
  175. for (auto& opt : projectTemplate.fileOptionsAndFiles)
  176. {
  177. optionVars.add (NewProjectTemplates::getVarForFileOption (opt.first));
  178. optionStrings.add (NewProjectTemplates::getStringForFileOption (opt.first));
  179. }
  180. return new ChoicePropertyComponent (fileOptionsValue, "File Creation Options", optionStrings, optionVars);
  181. }
  182. Array<PropertyComponent*> buildPropertyList()
  183. {
  184. PropertyListBuilder builder;
  185. builder.add (createProjectNamePropertyComponent());
  186. builder.add (createModulesPropertyComponent());
  187. builder.add (createModulePathPropertyComponent());
  188. builder.add (createExportersPropertyValue());
  189. if (! projectTemplate.fileOptionsAndFiles.empty())
  190. builder.add (createFileCreationOptionsPropertyComponent());
  191. return builder.components;
  192. }
  193. //==============================================================================
  194. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemplateComponent)
  195. };
  196. //==============================================================================
  197. class ExampleComponent : public Component
  198. {
  199. public:
  200. ExampleComponent (const File& f, std::function<void (const File&)> selectedCallback)
  201. : exampleFile (f),
  202. metadata (parseJUCEHeaderMetadata (exampleFile)),
  203. exampleSelectedCallback (std::move (selectedCallback)),
  204. header (metadata[Ids::name].toString(), metadata[Ids::description].toString(), BinaryData::background_logo_svg),
  205. codeViewer (doc, &cppTokeniser)
  206. {
  207. setTitle (exampleFile.getFileName());
  208. setFocusContainerType (FocusContainerType::focusContainer);
  209. addAndMakeVisible (header);
  210. openExampleButton.onClick = [this] { exampleSelectedCallback (exampleFile); };
  211. addAndMakeVisible (openExampleButton);
  212. setupCodeViewer();
  213. addAndMakeVisible (codeViewer);
  214. }
  215. void paint (Graphics& g) override
  216. {
  217. g.fillAll (findColour (secondaryBackgroundColourId));
  218. }
  219. void resized() override
  220. {
  221. auto bounds = getLocalBounds().reduced (10);
  222. header.setBounds (bounds.removeFromTop (125));
  223. openExampleButton.setBounds (bounds.removeFromBottom (30).removeFromRight (150));
  224. codeViewer.setBounds (bounds);
  225. }
  226. private:
  227. void setupCodeViewer()
  228. {
  229. auto fileString = exampleFile.loadFileAsString();
  230. doc.replaceAllContent (fileString);
  231. codeViewer.setScrollbarThickness (6);
  232. codeViewer.setReadOnly (true);
  233. codeViewer.setTitle ("Code");
  234. getAppSettings().appearance.applyToCodeEditor (codeViewer);
  235. codeViewer.scrollToLine (findBestLineToScrollToForClass (StringArray::fromLines (fileString),
  236. metadata[Ids::name].toString(),
  237. metadata[Ids::type] == "AudioProcessor"));
  238. }
  239. //==============================================================================
  240. File exampleFile;
  241. var metadata;
  242. std::function<void (const File&)> exampleSelectedCallback;
  243. ItemHeader header;
  244. CPlusPlusCodeTokeniser cppTokeniser;
  245. CodeDocument doc;
  246. CodeEditorComponent codeViewer;
  247. TextButton openExampleButton { "Open Example..." };
  248. //==============================================================================
  249. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ExampleComponent)
  250. };