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.

333 lines
12KB

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