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.

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