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.

273 lines
9.3KB

  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. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wredundant-move")
  117. return std::move (holder);
  118. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  119. }
  120. //==============================================================================
  121. struct ProjectTemplatesAndExamples : public TabbedComponent
  122. {
  123. ProjectTemplatesAndExamples (ContentComponent& c,
  124. std::function<void (std::unique_ptr<Project>&&)>&& newProjectCb,
  125. std::function<void (const File&)>&& exampleCb)
  126. : TabbedComponent (TabbedButtonBar::Orientation::TabsAtTop),
  127. content (c),
  128. exampleSelectedCallback (std::move (exampleCb))
  129. {
  130. addTab ("New Project", Colours::transparentBlack, createProjectTemplatesTab (content, std::move (newProjectCb)).release(), true);
  131. refreshExamplesTab();
  132. }
  133. void refreshExamplesTab()
  134. {
  135. auto wasOpen = (getCurrentTabIndex() == 1);
  136. removeTab (1);
  137. auto exampleTabs = createExampleProjectsTab (content, exampleSelectedCallback);
  138. addTab ("Open Example", Colours::transparentBlack, exampleTabs == nullptr ? new SetJUCEPathComponent (*this)
  139. : exampleTabs.release(),
  140. true);
  141. if (wasOpen)
  142. setCurrentTabIndex (1);
  143. }
  144. private:
  145. //==============================================================================
  146. struct SetJUCEPathComponent : public Component,
  147. private ChangeListener
  148. {
  149. explicit SetJUCEPathComponent (ProjectTemplatesAndExamples& o)
  150. : owner (o)
  151. {
  152. getGlobalProperties().addChangeListener (this);
  153. setPathButton.setButtonText ("Set path to JUCE...");
  154. setPathButton.onClick = [] { ProjucerApplication::getApp().showPathsWindow (true); };
  155. addAndMakeVisible (setPathButton);
  156. }
  157. ~SetJUCEPathComponent() override
  158. {
  159. getGlobalProperties().removeChangeListener (this);
  160. }
  161. void paint (Graphics& g) override
  162. {
  163. g.fillAll (findColour (secondaryBackgroundColourId));
  164. }
  165. void resized() override
  166. {
  167. auto bounds = getLocalBounds().reduced (5);
  168. bounds.removeFromTop (25);
  169. setPathButton.setBounds (bounds.removeFromTop (25));
  170. }
  171. private:
  172. void changeListenerCallback (ChangeBroadcaster*) override
  173. {
  174. if (isValidJUCEExamplesDirectory (ProjucerApplication::getJUCEExamplesDirectoryPathFromGlobal()))
  175. owner.refreshExamplesTab();
  176. }
  177. ProjectTemplatesAndExamples& owner;
  178. TextButton setPathButton;
  179. };
  180. ContentComponent& content;
  181. std::function<void (const File&)> exampleSelectedCallback;
  182. };
  183. //==============================================================================
  184. StartPageComponent::StartPageComponent (std::function<void (std::unique_ptr<Project>&&)>&& newProjectCb,
  185. std::function<void (const File&)>&& exampleCb)
  186. : content (std::make_unique<ContentComponent>()),
  187. tabs (std::make_unique<ProjectTemplatesAndExamples> (*content, std::move (newProjectCb), std::move (exampleCb)))
  188. {
  189. tabs->setOutline (0);
  190. addAndMakeVisible (*tabs);
  191. addAndMakeVisible (openExistingButton);
  192. openExistingButton.setCommandToTrigger (&ProjucerApplication::getCommandManager(), CommandIDs::open, true);
  193. addAndMakeVisible (*content);
  194. setSize (900, 600);
  195. }
  196. void StartPageComponent::paint (Graphics& g)
  197. {
  198. g.fillAll (findColour (backgroundColourId));
  199. }
  200. void StartPageComponent::resized()
  201. {
  202. auto bounds = getLocalBounds().reduced (10);
  203. auto tabBounds = bounds.removeFromLeft (bounds.getWidth() / 3);
  204. openExistingButton.setBounds (tabBounds.removeFromBottom (30).reduced (10, 0));
  205. tabBounds.removeFromBottom (5);
  206. tabs->setBounds (tabBounds);
  207. bounds.removeFromLeft (10);
  208. content->setBounds (bounds);
  209. }