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.

322 lines
11KB

  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. #include "../../Utility/UI/jucer_IconButton.h"
  21. #include "../../Utility/UI/jucer_UserSettingsPopup.h"
  22. //==============================================================================
  23. class HeaderComponent : public Component,
  24. private Button::Listener,
  25. private ComboBox::Listener,
  26. private ValueTree::Listener,
  27. private ChangeListener
  28. {
  29. public:
  30. HeaderComponent()
  31. : configLabel ("Config Label", "Selected exporter")
  32. {
  33. addAndMakeVisible (configLabel);
  34. addAndMakeVisible (exporterBox);
  35. exporterBox.addListener (this);
  36. addAndMakeVisible (juceIcon = new ImageComponent ("icon"));
  37. juceIcon->setImage (ImageCache::getFromMemory (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize),
  38. RectanglePlacement::centred);
  39. projectNameLabel.setText (String(), dontSendNotification);
  40. addAndMakeVisible (projectNameLabel);
  41. initialiseButtons();
  42. }
  43. ~HeaderComponent()
  44. {
  45. if (userSettingsWindow != nullptr)
  46. userSettingsWindow->dismiss();
  47. }
  48. void resized() override
  49. {
  50. auto bounds = getLocalBounds();
  51. configLabel.setFont (Font (bounds.getHeight() / 3.0f));
  52. //======================================================================
  53. auto projectHeaderBounds = bounds.removeFromLeft (tabsWidth);
  54. juceIcon->setBounds (projectHeaderBounds.removeFromLeft (projectHeaderBounds.getHeight()).reduced (5, 5));
  55. projectSettingsButton->setBounds (projectHeaderBounds.removeFromRight (projectHeaderBounds.getHeight()).reduced (2, 2));
  56. projectNameLabel.setBounds (projectHeaderBounds);
  57. //======================================================================
  58. bounds.removeFromLeft (33);
  59. continuousRebuildButton->setBounds (bounds.removeFromLeft (bounds.getHeight()).reduced (2, 2));
  60. bounds.removeFromLeft (5);
  61. buildNowButton->setBounds (bounds.removeFromLeft (bounds.getHeight()).reduced (2, 2));
  62. bounds.removeFromRight (5);
  63. userSettingsButton->setBounds (bounds.removeFromRight (bounds.getHeight()).reduced (2, 2));
  64. auto exporterWidth = jmax (250, bounds.getWidth() / 2);
  65. auto spacing = bounds.getWidth() - exporterWidth;
  66. auto leftSpacing = jmax (20, spacing / 3);
  67. auto rightSpacing = jmax (40, 2 * (spacing / 3));
  68. bounds.removeFromLeft (leftSpacing);
  69. bounds.removeFromRight (rightSpacing);
  70. saveAndOpenInIDEButton->setBounds (bounds.removeFromRight (bounds.getHeight()).reduced (2, 2));
  71. bounds.removeFromRight (5);
  72. exporterSettingsButton->setBounds (bounds.removeFromRight (bounds.getHeight()).reduced (2, 2));
  73. bounds.removeFromRight (10);
  74. exporterBox.setBounds (bounds.removeFromBottom (roundToInt (bounds.getHeight() / 1.8f)));
  75. configLabel.setBounds (bounds);
  76. }
  77. void paint (Graphics& g) override
  78. {
  79. g.fillAll (findColour (backgroundColourId));
  80. }
  81. void setCurrentProject (Project* p)
  82. {
  83. project = p;
  84. exportersTree = project->getExporters();
  85. exportersTree.addListener (this);
  86. updateExporters();
  87. project->addChangeListener (this);
  88. updateName();
  89. if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>())
  90. updateBuildButtons (pcc->isBuildEnabled(), pcc->isContinuousRebuildEnabled());
  91. }
  92. void updateExporters()
  93. {
  94. auto selectedName = getSelectedExporterName();
  95. exporterBox.clear();
  96. auto preferredExporterIndex = -1;
  97. int i = 0;
  98. for (Project::ExporterIterator exporter (*project); exporter.next(); ++i)
  99. {
  100. exporterBox.addItem (exporter->getName(), i + 1);
  101. if (selectedName == exporter->getName())
  102. exporterBox.setSelectedId (i + 1);
  103. if (exporter->canLaunchProject() && preferredExporterIndex == -1)
  104. preferredExporterIndex = i;
  105. }
  106. if (exporterBox.getSelectedItemIndex() == -1)
  107. exporterBox.setSelectedItemIndex (preferredExporterIndex != -1 ? preferredExporterIndex
  108. : 0);
  109. updateExporterButton();
  110. }
  111. String getSelectedExporterName()
  112. {
  113. return exporterBox.getItemText (exporterBox.getSelectedItemIndex());
  114. }
  115. bool canCurrentExporterLaunchProject()
  116. {
  117. for (Project::ExporterIterator exporter (*project); exporter.next();)
  118. if (exporter->getName() == getSelectedExporterName() && exporter->canLaunchProject())
  119. return true;
  120. return false;
  121. }
  122. int getUserButtonWidth() { return userSettingsButton->getWidth(); }
  123. void sidebarTabsWidthChanged (int newWidth)
  124. {
  125. tabsWidth = newWidth;
  126. resized();
  127. }
  128. void showUserSettings()
  129. {
  130. #if JUCER_ENABLE_GPL_MODE
  131. auto settingsPopupHeight = 40;
  132. auto settingsPopupWidth = 200;
  133. #else
  134. auto settingsPopupHeight = 150;
  135. auto settingsPopupWidth = 250;
  136. #endif
  137. auto* content = new UserSettingsPopup (false);
  138. content->setSize (settingsPopupWidth, settingsPopupHeight);
  139. userSettingsWindow = &CallOutBox::launchAsynchronously (content, userSettingsButton->getScreenBounds(), nullptr);
  140. }
  141. void updateBuildButtons (bool isBuildEnabled, bool isContinuousRebuildEnabled)
  142. {
  143. buildNowButton->setEnabled (isBuildEnabled && ! isContinuousRebuildEnabled);
  144. continuousRebuildButton->setEnabled (isBuildEnabled);
  145. continuousRebuildButton->icon = Icon (isContinuousRebuildEnabled ? &getIcons().continuousBuildStop : &getIcons().continuousBuildStart,
  146. Colours::transparentBlack);
  147. repaint();
  148. }
  149. void lookAndFeelChanged() override
  150. {
  151. if (userSettingsWindow != nullptr)
  152. userSettingsWindow->sendLookAndFeelChange();
  153. }
  154. private:
  155. Project* project = nullptr;
  156. ValueTree exportersTree;
  157. Label configLabel, projectNameLabel;
  158. ComboBox exporterBox;
  159. ScopedPointer<ImageComponent> juceIcon;
  160. ScopedPointer<IconButton> projectSettingsButton, continuousRebuildButton, buildNowButton,
  161. exporterSettingsButton, saveAndOpenInIDEButton, userSettingsButton;
  162. SafePointer<CallOutBox> userSettingsWindow;
  163. int tabsWidth = 200;
  164. //==========================================================================
  165. void buttonClicked (Button* b) override
  166. {
  167. auto* pcc = findParentComponentOfClass<ProjectContentComponent>();
  168. if (b == projectSettingsButton) pcc->showProjectSettings();
  169. else if (b == continuousRebuildButton) pcc->setContinuousRebuildEnabled (! pcc->isContinuousRebuildEnabled());
  170. else if (b == buildNowButton) pcc->rebuildNow();
  171. else if (b == exporterSettingsButton) pcc->showExporterSettings (getSelectedExporterName());
  172. else if (b == saveAndOpenInIDEButton) pcc->openInSelectedIDE (true);
  173. else if (b == userSettingsButton) showUserSettings();
  174. }
  175. void comboBoxChanged (ComboBox* c) override
  176. {
  177. if (c == &exporterBox)
  178. updateExporterButton();
  179. }
  180. void changeListenerCallback (ChangeBroadcaster* source) override
  181. {
  182. if (source == project)
  183. {
  184. updateName();
  185. updateExporters();
  186. }
  187. }
  188. void valueTreePropertyChanged (ValueTree&, const Identifier&) override {}
  189. void valueTreeParentChanged (ValueTree&) override {}
  190. void valueTreeChildAdded (ValueTree& parentTree, ValueTree&) override { updateIfNeeded (parentTree); }
  191. void valueTreeChildRemoved (ValueTree& parentTree, ValueTree&, int) override { updateIfNeeded (parentTree); }
  192. void valueTreeChildOrderChanged (ValueTree& parentTree, int, int) override { updateIfNeeded (parentTree); }
  193. void initialiseButtons()
  194. {
  195. auto& icons = getIcons();
  196. addAndMakeVisible (projectSettingsButton = new IconButton ("Project Settings", &icons.settings));
  197. projectSettingsButton->addListener (this);
  198. addAndMakeVisible (continuousRebuildButton = new IconButton ("Continuous Rebuild", &icons.continuousBuildStart));
  199. continuousRebuildButton->addListener (this);
  200. addAndMakeVisible (buildNowButton = new IconButton ("Build Now", &icons.buildNow));
  201. buildNowButton->addListener (this);
  202. addAndMakeVisible (exporterSettingsButton = new IconButton ("Exporter Settings", &icons.edit));
  203. exporterSettingsButton->addListener (this);
  204. addAndMakeVisible (saveAndOpenInIDEButton = new IconButton ("Save and Open in IDE", nullptr));
  205. saveAndOpenInIDEButton->addListener (this);
  206. saveAndOpenInIDEButton->isIDEButton = true;
  207. addAndMakeVisible (userSettingsButton = new IconButton ("User Settings", &icons.user));
  208. userSettingsButton->addListener (this);
  209. userSettingsButton->isUserButton = true;
  210. updateExporterButton();
  211. updateUserAvatar();
  212. }
  213. void updateIfNeeded (ValueTree tree)
  214. {
  215. if (tree == exportersTree)
  216. updateExporters();
  217. }
  218. void updateName()
  219. {
  220. projectNameLabel.setText (project->getDocumentTitle(), dontSendNotification);
  221. }
  222. void updateExporterButton()
  223. {
  224. auto currentExporterName = getSelectedExporterName();
  225. for (auto info : ProjectExporter::getExporterTypes())
  226. {
  227. if (currentExporterName.contains (info.name))
  228. {
  229. saveAndOpenInIDEButton->iconImage = info.getIcon();
  230. saveAndOpenInIDEButton->repaint();
  231. saveAndOpenInIDEButton->setEnabled (canCurrentExporterLaunchProject());
  232. }
  233. }
  234. }
  235. void updateUserAvatar()
  236. {
  237. if (LicenseController* controller = ProjucerApplication::getApp().licenseController)
  238. {
  239. auto state = controller->getState();
  240. userSettingsButton->iconImage = state.avatar;
  241. userSettingsButton->repaint();
  242. }
  243. }
  244. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HeaderComponent)
  245. };