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.

271 lines
9.2KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - 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 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-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. #include "../jucer_Headers.h"
  19. #include "../jucer_Application.h"
  20. #include "jucer_StartPageComponent.h"
  21. #include "jucer_StartPageTreeHolder.h"
  22. #include "jucer_NewProjectTemplates.h"
  23. #include "jucer_ContentComponents.h"
  24. //==============================================================================
  25. struct ContentComponent : public Component
  26. {
  27. void resized() override
  28. {
  29. if (content != nullptr)
  30. content->setBounds (getLocalBounds());
  31. }
  32. void setContent (std::unique_ptr<Component>&& newContent)
  33. {
  34. if (content.get() != newContent.get())
  35. {
  36. content = std::move (newContent);
  37. addAndMakeVisible (content.get());
  38. resized();
  39. }
  40. }
  41. private:
  42. std::unique_ptr<Component> content;
  43. //==============================================================================
  44. JUCE_LEAK_DETECTOR (ContentComponent)
  45. };
  46. //==============================================================================
  47. static File findExampleFile (int dirIndex, int index)
  48. {
  49. auto dir = ProjucerApplication::getSortedExampleDirectories()[dirIndex];
  50. return ProjucerApplication::getSortedExampleFilesInDirectory (dir)[index];
  51. }
  52. static std::unique_ptr<Component> createExampleProjectsTab (ContentComponent& content, std::function<void (const File&)> cb)
  53. {
  54. StringArray exampleCategories;
  55. std::vector<StringArray> examples;
  56. for (auto& dir : ProjucerApplication::getSortedExampleDirectories())
  57. {
  58. exampleCategories.add (dir.getFileName());
  59. StringArray ex;
  60. for (auto& f : ProjucerApplication::getSortedExampleFilesInDirectory (dir))
  61. ex.add (f.getFileNameWithoutExtension());
  62. examples.push_back (ex);
  63. }
  64. if (exampleCategories.isEmpty())
  65. return nullptr;
  66. auto selectedCallback = [&, cb] (int category, int index) mutable
  67. {
  68. content.setContent (std::make_unique<ExampleComponent> (findExampleFile (category, index), cb));
  69. };
  70. return std::make_unique<StartPageTreeHolder> (exampleCategories,
  71. examples,
  72. std::move (selectedCallback),
  73. StartPageTreeHolder::Open::no);
  74. }
  75. //==============================================================================
  76. static StringArray getAllTemplateCategoryStrings()
  77. {
  78. StringArray categories;
  79. for (auto& t : NewProjectTemplates::getAllTemplates())
  80. categories.addIfNotAlreadyThere (NewProjectTemplates::getProjectCategoryString (t.category));
  81. return categories;
  82. }
  83. static std::vector<NewProjectTemplates::ProjectTemplate> getTemplatesInCategory (const String& category)
  84. {
  85. std::vector<NewProjectTemplates::ProjectTemplate> templates;
  86. for (auto& t : NewProjectTemplates::getAllTemplates())
  87. if (NewProjectTemplates::getProjectCategoryString (t.category) == category)
  88. templates.push_back (t);
  89. return templates;
  90. }
  91. static StringArray getAllTemplateNamesForCategory (const String& category)
  92. {
  93. StringArray types;
  94. for (auto& t : getTemplatesInCategory (category))
  95. types.add (t.displayName);
  96. return types;
  97. }
  98. static std::unique_ptr<Component> createProjectTemplatesTab (ContentComponent& content,
  99. std::function<void (std::unique_ptr<Project>&&)>&& cb)
  100. {
  101. auto categories = getAllTemplateCategoryStrings();
  102. std::vector<StringArray> templateNames;
  103. for (auto& c : categories)
  104. templateNames.push_back (getAllTemplateNamesForCategory (c));
  105. auto selectedCallback = [&, cb] (int category, int index)
  106. {
  107. auto categoryString = getAllTemplateCategoryStrings()[category];
  108. auto templates = getTemplatesInCategory (categoryString);
  109. content.setContent (std::make_unique<TemplateComponent> (templates[(size_t) index], std::move (cb)));
  110. };
  111. auto holder = std::make_unique<StartPageTreeHolder> (categories,
  112. templateNames,
  113. std::move (selectedCallback),
  114. StartPageTreeHolder::Open::yes);
  115. holder->setSelectedItem (categories[0], 1);
  116. return std::move (holder);
  117. }
  118. //==============================================================================
  119. struct ProjectTemplatesAndExamples : public TabbedComponent
  120. {
  121. ProjectTemplatesAndExamples (ContentComponent& c,
  122. std::function<void (std::unique_ptr<Project>&&)>&& newProjectCb,
  123. std::function<void (const File&)>&& exampleCb)
  124. : TabbedComponent (TabbedButtonBar::Orientation::TabsAtTop),
  125. content (c),
  126. exampleSelectedCallback (std::move (exampleCb))
  127. {
  128. addTab ("New Project", Colours::transparentBlack, createProjectTemplatesTab (content, std::move (newProjectCb)).release(), true);
  129. refreshExamplesTab();
  130. }
  131. void refreshExamplesTab()
  132. {
  133. auto wasOpen = (getCurrentTabIndex() == 1);
  134. removeTab (1);
  135. auto exampleTabs = createExampleProjectsTab (content, exampleSelectedCallback);
  136. addTab ("Open Example", Colours::transparentBlack, exampleTabs == nullptr ? new SetJUCEPathComponent (*this)
  137. : exampleTabs.release(),
  138. true);
  139. if (wasOpen)
  140. setCurrentTabIndex (1);
  141. }
  142. private:
  143. //==============================================================================
  144. struct SetJUCEPathComponent : public Component,
  145. private ChangeListener
  146. {
  147. explicit SetJUCEPathComponent (ProjectTemplatesAndExamples& o)
  148. : owner (o)
  149. {
  150. getGlobalProperties().addChangeListener (this);
  151. setPathButton.setButtonText ("Set path to JUCE...");
  152. setPathButton.onClick = [] { ProjucerApplication::getApp().showPathsWindow (true); };
  153. addAndMakeVisible (setPathButton);
  154. }
  155. ~SetJUCEPathComponent() override
  156. {
  157. getGlobalProperties().removeChangeListener (this);
  158. }
  159. void paint (Graphics& g) override
  160. {
  161. g.fillAll (findColour (secondaryBackgroundColourId));
  162. }
  163. void resized() override
  164. {
  165. auto bounds = getLocalBounds().reduced (5);
  166. bounds.removeFromTop (25);
  167. setPathButton.setBounds (bounds.removeFromTop (25));
  168. }
  169. private:
  170. void changeListenerCallback (ChangeBroadcaster*) override
  171. {
  172. if (isValidJUCEExamplesDirectory (ProjucerApplication::getJUCEExamplesDirectoryPathFromGlobal()))
  173. owner.refreshExamplesTab();
  174. }
  175. ProjectTemplatesAndExamples& owner;
  176. TextButton setPathButton;
  177. };
  178. ContentComponent& content;
  179. std::function<void (const File&)> exampleSelectedCallback;
  180. };
  181. //==============================================================================
  182. StartPageComponent::StartPageComponent (std::function<void (std::unique_ptr<Project>&&)>&& newProjectCb,
  183. std::function<void (const File&)>&& exampleCb)
  184. : content (std::make_unique<ContentComponent>()),
  185. tabs (std::make_unique<ProjectTemplatesAndExamples> (*content, std::move (newProjectCb), std::move (exampleCb)))
  186. {
  187. tabs->setOutline (0);
  188. addAndMakeVisible (*tabs);
  189. addAndMakeVisible (openExistingButton);
  190. openExistingButton.setCommandToTrigger (&ProjucerApplication::getCommandManager(), CommandIDs::open, true);
  191. addAndMakeVisible (*content);
  192. setSize (900, 600);
  193. }
  194. void StartPageComponent::paint (Graphics& g)
  195. {
  196. g.fillAll (findColour (backgroundColourId));
  197. }
  198. void StartPageComponent::resized()
  199. {
  200. auto bounds = getLocalBounds().reduced (10);
  201. auto tabBounds = bounds.removeFromLeft (bounds.getWidth() / 3);
  202. openExistingButton.setBounds (tabBounds.removeFromBottom (30).reduced (10, 0));
  203. tabBounds.removeFromBottom (5);
  204. tabs->setBounds (tabBounds);
  205. bounds.removeFromLeft (10);
  206. content->setBounds (bounds);
  207. }