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.

281 lines
9.9KB

  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. /**
  22. Template option tile button.
  23. The drawable button object class for the tile icons and buttons in the TemplateTileBrowser
  24. */
  25. class TemplateOptionButton : public DrawableButton
  26. {
  27. public:
  28. TemplateOptionButton (const String& buttonName, ButtonStyle buttonStyle, const char* thumbSvg)
  29. : DrawableButton (buttonName, buttonStyle)
  30. {
  31. // svg for thumbnail icon
  32. ScopedPointer<XmlElement> svg (XmlDocument::parse (thumbSvg));
  33. jassert (svg != nullptr);
  34. thumb = Drawable::createFromSVG (*svg);
  35. // svg for thumbnail background highlight
  36. ScopedPointer<XmlElement> backSvg (XmlDocument::parse (BinaryData::wizard_Highlight_svg));
  37. jassert (backSvg != nullptr);
  38. hoverBackground = Drawable::createFromSVG (*backSvg);
  39. name = buttonName;
  40. description = "<insert description>";
  41. }
  42. void paintButton (Graphics& g, bool isMouseOverButton, bool /*isButtonDown*/) override
  43. {
  44. const Rectangle<float> r (getLocalBounds().toFloat());
  45. const Colour buttonColour (0xffA35E93);
  46. if (isMouseOverButton)
  47. {
  48. if (getStyle() == ImageFitted)
  49. {
  50. hoverBackground->drawWithin (g, r, RectanglePlacement::centred, 1.0);
  51. thumb->drawWithin (g, r, RectanglePlacement::centred, 1.0);
  52. }
  53. else
  54. {
  55. g.setColour (buttonColour.withAlpha (0.3f));
  56. g.fillRoundedRectangle (r.reduced (2.0f, 2.0f), 10.0f);
  57. g.setColour (buttonColour);
  58. g.drawRoundedRectangle (r.reduced (2.0f, 2.0f), 10.0f, 2.0f);
  59. }
  60. }
  61. else
  62. {
  63. if (getStyle() == ImageFitted)
  64. {
  65. thumb->drawWithin (g, r, RectanglePlacement::centred, 1.0);
  66. }
  67. else
  68. {
  69. g.setColour (buttonColour);
  70. g.drawRoundedRectangle (r.reduced (2.0f, 2.0f), 10.0f, 2.0f);
  71. }
  72. }
  73. Rectangle<float> textTarget;
  74. // center the text for the text buttons or position the text in the image buttons
  75. if (getStyle() != ImageFitted)
  76. {
  77. textTarget = getLocalBounds().toFloat();
  78. }
  79. else
  80. {
  81. textTarget = RectanglePlacement (RectanglePlacement::centred).appliedTo (thumb->getDrawableBounds(), r);
  82. textTarget = textTarget.removeFromBottom (textTarget.getHeight() * 0.3f);
  83. }
  84. g.setColour (findColour (defaultTextColourId));
  85. g.drawText (name, textTarget, Justification::centred, true);
  86. }
  87. void resized() override
  88. {
  89. thumb->setBoundsToFit (0, 0, getWidth(), getHeight(), Justification::centred, false);
  90. }
  91. void setDescription (String descript) noexcept
  92. {
  93. description = descript;
  94. }
  95. String getDescription() const noexcept
  96. {
  97. return description;
  98. }
  99. private:
  100. ScopedPointer<Drawable> thumb, hoverBackground;
  101. String name, description;
  102. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemplateOptionButton)
  103. };
  104. //==============================================================================
  105. /**
  106. Project Template Component for front page.
  107. Features multiple icon buttons to select the type of project template
  108. */
  109. class TemplateTileBrowser : public Component,
  110. private Button::Listener
  111. {
  112. public:
  113. TemplateTileBrowser (WizardComp* projectWizard)
  114. {
  115. const int numWizardButtons = getNumWizards() - 1; // ( - 1 because the last one is blank)
  116. for (int i = 0; i < numWizardButtons; ++i)
  117. {
  118. ScopedPointer<NewProjectWizard> wizard (createWizardType (i));
  119. TemplateOptionButton* b = new TemplateOptionButton (wizard->getName(),
  120. TemplateOptionButton::ImageFitted,
  121. wizard->getIcon());
  122. optionButtons.add (b);
  123. addAndMakeVisible (b);
  124. b->setDescription (wizard->getDescription());
  125. b->addListener (this);
  126. }
  127. // Handle Open Project button functionality
  128. ApplicationCommandManager& commandManager = ProjucerApplication::getCommandManager();
  129. addAndMakeVisible (blankProjectButton = new TemplateOptionButton ("Create Blank Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg));
  130. addAndMakeVisible (exampleProjectButton = new TemplateOptionButton ("Open Example Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg));
  131. addAndMakeVisible (openProjectButton = new TemplateOptionButton ("Open Existing Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg));
  132. blankProjectButton->addListener (this);
  133. exampleProjectButton->addListener (this);
  134. openProjectButton->setCommandToTrigger (&commandManager, CommandIDs::open, true);
  135. newProjectWizard = projectWizard;
  136. }
  137. void paint (Graphics& g) override
  138. {
  139. g.setColour (findColour (contentHeaderBackgroundColourId));
  140. g.fillRect (getLocalBounds().removeFromTop (60));
  141. g.setColour (Colours::white);
  142. g.setFont (20.0f);
  143. g.drawText ("Create New Project", 0, 0, getWidth(), 60, Justification::centred, true);
  144. auto descriptionBox = (getLocalBounds().reduced (30).removeFromBottom (50));
  145. g.setColour (findColour (defaultTextColourId));
  146. g.setFont (15.0f);
  147. for (int i = 0; i < optionButtons.size(); ++i)
  148. if (optionButtons.getUnchecked(i)->isOver())
  149. g.drawFittedText (optionButtons.getUnchecked(i)->getDescription(), descriptionBox, Justification::centred, 5, 1.0f);
  150. }
  151. void resized() override
  152. {
  153. auto allOpts = getLocalBounds().reduced (40, 60);
  154. allOpts.removeFromBottom (allOpts.getHeight() / 4);
  155. const auto numHorizIcons = 4;
  156. const auto optStep = allOpts.getWidth() / numHorizIcons;
  157. for (int i = 0; i < optionButtons.size(); ++i)
  158. {
  159. const auto yShift = i < numHorizIcons ? 0 : 1;
  160. optionButtons.getUnchecked(i)->setBounds (Rectangle<int> (allOpts.getX() + (i % numHorizIcons) * optStep,
  161. allOpts.getY() + yShift * allOpts.getHeight() / 2,
  162. optStep, allOpts.getHeight() / 2)
  163. .reduced (10, 10));
  164. }
  165. auto openButtonBounds = getLocalBounds();
  166. openButtonBounds.removeFromBottom (proportionOfHeight (0.12f));
  167. openButtonBounds = openButtonBounds.removeFromBottom (120);
  168. openButtonBounds.reduce (50, 40);
  169. blankProjectButton->setBounds (openButtonBounds.removeFromLeft (optStep - 20));
  170. exampleProjectButton->setBounds (openButtonBounds.removeFromRight (optStep - 20));
  171. openProjectButton->setBounds (openButtonBounds.reduced (18, 0));
  172. }
  173. void showWizard (const String& name)
  174. {
  175. newProjectWizard->projectType.setText (name);
  176. if (SlidingPanelComponent* parent = findParentComponentOfClass<SlidingPanelComponent>())
  177. parent->goToTab (1);
  178. else
  179. jassertfalse;
  180. }
  181. void createBlankProject()
  182. {
  183. showWizard (BlankAppWizard().getName());
  184. }
  185. void openExampleProject()
  186. {
  187. FileChooser fc ("Open File", findExamplesFolder());
  188. if (fc.browseForFileToOpen())
  189. ProjucerApplication::getApp().openFile (fc.getResult());
  190. }
  191. static File findExamplesFolder()
  192. {
  193. File appFolder (File::getSpecialLocation (File::currentApplicationFile));
  194. while (appFolder.exists()
  195. && appFolder.getParentDirectory() != appFolder)
  196. {
  197. File examples (appFolder.getSiblingFile ("examples"));
  198. if (examples.exists())
  199. return examples;
  200. appFolder = appFolder.getParentDirectory();
  201. }
  202. return {};
  203. }
  204. private:
  205. OwnedArray<TemplateOptionButton> optionButtons;
  206. NewProjectWizardClasses::WizardComp* newProjectWizard;
  207. ScopedPointer<TemplateOptionButton> blankProjectButton, openProjectButton, exampleProjectButton;
  208. void buttonClicked (Button* b) override
  209. {
  210. if (b == blankProjectButton)
  211. createBlankProject();
  212. else if (b == exampleProjectButton)
  213. openExampleProject();
  214. else if (dynamic_cast<TemplateOptionButton*> (b) != nullptr)
  215. showWizard (b->getButtonText());
  216. }
  217. void buttonStateChanged (Button*) override
  218. {
  219. repaint();
  220. }
  221. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemplateTileBrowser)
  222. };