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
10KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #pragma once
  18. //==============================================================================
  19. /**
  20. Template option tile button.
  21. The drawable button object class for the tile icons and buttons in the TemplateTileBrowser
  22. */
  23. class TemplateOptionButton : public DrawableButton
  24. {
  25. public:
  26. TemplateOptionButton (const String& buttonName, ButtonStyle buttonStyle, const char* thumbSvg)
  27. : DrawableButton (buttonName, buttonStyle)
  28. {
  29. // svg for thumbnail icon
  30. ScopedPointer<XmlElement> svg (XmlDocument::parse (thumbSvg));
  31. jassert (svg != nullptr);
  32. thumb = Drawable::createFromSVG (*svg);
  33. // svg for thumbnail background highlight
  34. ScopedPointer<XmlElement> backSvg (XmlDocument::parse (BinaryData::wizard_Highlight_svg));
  35. jassert (backSvg != nullptr);
  36. hoverBackground = Drawable::createFromSVG (*backSvg);
  37. name = buttonName;
  38. description = "<insert description>";
  39. }
  40. void paintButton (Graphics& g, bool isMouseOverButton, bool /*isButtonDown*/) override
  41. {
  42. const Rectangle<float> r (getLocalBounds().toFloat());
  43. const Colour buttonColour (0xfff29300);
  44. if (isMouseOverButton)
  45. {
  46. if (getStyle() == ImageFitted)
  47. {
  48. hoverBackground->drawWithin (g, r, RectanglePlacement::centred, 1.0);
  49. thumb->drawWithin (g, r, RectanglePlacement::centred, 1.0);
  50. }
  51. else
  52. {
  53. g.setColour (buttonColour.withAlpha (0.3f));
  54. g.fillRoundedRectangle (r.reduced (2.0f, 2.0f), 10.0f);
  55. g.setColour (buttonColour);
  56. g.drawRoundedRectangle (r.reduced (2.0f, 2.0f), 10.0f, 2.0f);
  57. }
  58. }
  59. else
  60. {
  61. if (getStyle() == ImageFitted)
  62. {
  63. thumb->drawWithin (g, r, RectanglePlacement::centred, 1.0);
  64. }
  65. else
  66. {
  67. g.setColour (buttonColour);
  68. g.drawRoundedRectangle (r.reduced (2.0f, 2.0f), 10.0f, 2.0f);
  69. }
  70. }
  71. Rectangle<float> textTarget;
  72. // center the text for the text buttons or position the text in the image buttons
  73. if (getStyle() != ImageFitted)
  74. {
  75. textTarget = getLocalBounds().toFloat();
  76. }
  77. else
  78. {
  79. textTarget = RectanglePlacement (RectanglePlacement::centred).appliedTo (thumb->getDrawableBounds(), r);
  80. textTarget = textTarget.removeFromBottom (textTarget.getHeight() * 0.3f);
  81. }
  82. g.setColour (findColour (mainBackgroundColourId).contrasting());
  83. g.drawText (name, textTarget, Justification::centred, true);
  84. }
  85. void resized() override
  86. {
  87. thumb->setBoundsToFit (0, 0, getWidth(), getHeight(), Justification::centred, false);
  88. }
  89. void setDescription (String descript) noexcept
  90. {
  91. description = descript;
  92. }
  93. String getDescription() const noexcept
  94. {
  95. return description;
  96. }
  97. private:
  98. ScopedPointer<Drawable> thumb, hoverBackground;
  99. String name, description;
  100. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemplateOptionButton)
  101. };
  102. //==============================================================================
  103. /**
  104. Project Template Component for front page.
  105. Features multiple icon buttons to select the type of project template
  106. */
  107. class TemplateTileBrowser : public Component,
  108. private Button::Listener
  109. {
  110. public:
  111. TemplateTileBrowser (WizardComp* projectWizard)
  112. {
  113. const int numWizardButtons = getNumWizards() - 1; // ( - 1 because the last one is blank)
  114. for (int i = 0; i < numWizardButtons; ++i)
  115. {
  116. ScopedPointer<NewProjectWizard> wizard (createWizardType (i));
  117. TemplateOptionButton* b = new TemplateOptionButton (wizard->getName(),
  118. TemplateOptionButton::ImageFitted,
  119. wizard->getIcon());
  120. optionButtons.add (b);
  121. addAndMakeVisible (b);
  122. b->setDescription (wizard->getDescription());
  123. b->addListener (this);
  124. }
  125. // Handle Open Project button functionality
  126. ApplicationCommandManager& commandManager = ProjucerApplication::getCommandManager();
  127. addAndMakeVisible (blankProjectButton = new TemplateOptionButton ("Create Blank Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg));
  128. addAndMakeVisible (exampleProjectButton = new TemplateOptionButton ("Open Example Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg));
  129. addAndMakeVisible (openProjectButton = new TemplateOptionButton ("Open Existing Project", TemplateOptionButton::ImageOnButtonBackground, BinaryData::wizard_Openfile_svg));
  130. blankProjectButton->addListener (this);
  131. exampleProjectButton->addListener (this);
  132. openProjectButton->setCommandToTrigger (&commandManager, CommandIDs::open, true);
  133. newProjectWizard = projectWizard;
  134. }
  135. void paint (Graphics& g) override
  136. {
  137. g.setColour (Colours::black.withAlpha (0.2f));
  138. g.fillRect (getLocalBounds().removeFromTop (60));
  139. g.setColour (Colours::white);
  140. g.setFont (20.0f);
  141. g.drawText ("Create New Project", 0, 0, getWidth(), 60, Justification::centred, true);
  142. // draw the descriptions of each template if hovered;
  143. // (repaint is called by the button listener on change state)
  144. Rectangle<int> descriptionBox (getLocalBounds().reduced (30).removeFromBottom (50));
  145. g.setColour (Colours::white.withAlpha (0.4f));
  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. Rectangle<int> allOpts = getLocalBounds().reduced (40, 60);
  154. allOpts.removeFromBottom (allOpts.getHeight() / 4);
  155. const int numHorizIcons = 4;
  156. const int optStep = allOpts.getWidth() / numHorizIcons;
  157. for (int i = 0; i < optionButtons.size(); ++i)
  158. {
  159. const int 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. Rectangle<int> 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 File();
  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. };