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.

247 lines
10KB

  1. #include "ConfigurePopover.hpp"
  2. namespace {
  3. constexpr int TEXT_HEIGHT {16};
  4. juce::Colour stateToLabelColour(bool state) {
  5. if (state) {
  6. return UIUtils::highlightColour;
  7. }
  8. return UIUtils::highlightColour.withAlpha(0.5f);
  9. }
  10. int getHeightForLabelText(juce::String text) {
  11. const int numLines = juce::StringArray::fromTokens(text, "\n").size();
  12. return TEXT_HEIGHT * numLines;
  13. }
  14. void removePathFromSearchPaths(juce::FileSearchPath& searchPaths, juce::String path) {
  15. for (int pathNumber {0}; pathNumber < searchPaths.getNumPaths(); pathNumber++) {
  16. if (searchPaths[pathNumber].getFullPathName() == path) {
  17. searchPaths.remove(pathNumber);
  18. return;
  19. }
  20. }
  21. }
  22. }
  23. CustomPathsList::CustomPathsList(juce::FileSearchPath& customPaths) : _customPaths(customPaths) {
  24. rebuild();
  25. }
  26. CustomPathsList::~CustomPathsList() {
  27. }
  28. void CustomPathsList::resized() {
  29. juce::Rectangle<int> availableArea = getLocalBounds();
  30. for (auto& label : _customPathsLabels) {
  31. label->setBounds(availableArea.removeFromTop(TEXT_HEIGHT));
  32. }
  33. }
  34. void CustomPathsList::mouseDown(const juce::MouseEvent& event) {
  35. if (!event.mods.isRightButtonDown()) {
  36. return;
  37. }
  38. if (auto label = dynamic_cast<juce::Label*>(event.eventComponent); label != nullptr) {
  39. removePathFromSearchPaths(_customPaths, label->getText());
  40. rebuild();
  41. resized();
  42. }
  43. }
  44. int CustomPathsList::getRequiredHeight() const {
  45. return TEXT_HEIGHT * _customPathsLabels.size();
  46. }
  47. void CustomPathsList::rebuild() {
  48. _customPathsLabels.clear();
  49. for (int pathNumber {0}; pathNumber < _customPaths.getNumPaths(); pathNumber++) {
  50. auto thisLabel = std::make_unique<juce::Label>(
  51. "Path " + juce::String(pathNumber) + " Label",
  52. _customPaths[pathNumber].getFullPathName()
  53. );
  54. addAndMakeVisible(thisLabel.get());
  55. thisLabel->setFont(juce::Font(15.00f, juce::Font::plain).withTypefaceStyle("Regular"));
  56. thisLabel->setJustificationType(juce::Justification::verticallyCentred | juce::Justification::horizontallyCentred);
  57. thisLabel->setEditable(false, false, false);
  58. thisLabel->setColour(juce::Label::textColourId, UIUtils::highlightColour);
  59. thisLabel->addMouseListener(this, false);
  60. thisLabel->setTooltip("Right click to remove");
  61. _customPathsLabels.push_back(std::move(thisLabel));
  62. }
  63. }
  64. FormatConfigureComponent::FormatConfigureComponent(
  65. juce::AudioPluginFormat* format,
  66. bool& defaultPathsEnabled,
  67. juce::FileSearchPath& customPaths) {
  68. const juce::String formatName = format->getName();
  69. _defaultPathsListLabel.reset(new juce::Label(formatName + " Default Paths List Label", format->getDefaultLocationsToSearch().toStringWithSeparator("\n")));
  70. addAndMakeVisible(_defaultPathsListLabel.get());
  71. _defaultPathsListLabel->setFont(juce::Font(15.00f, juce::Font::plain).withTypefaceStyle("Regular"));
  72. _defaultPathsListLabel->setJustificationType(juce::Justification::verticallyCentred | juce::Justification::horizontallyCentred);
  73. _defaultPathsListLabel->setEditable(false, false, false);
  74. _defaultPathsListLabel->setColour(juce::Label::textColourId, stateToLabelColour(defaultPathsEnabled));
  75. _defaultPathsButton.reset(new juce::TextButton(formatName + " Default Paths Button"));
  76. addAndMakeVisible(_defaultPathsButton.get());
  77. _defaultPathsButton->setButtonText(TRANS("Include " + formatName + " Default Paths"));
  78. _defaultPathsButton->setLookAndFeel(&_toggleButtonLookAndFeel);
  79. _defaultPathsButton->setColour(UIUtils::ToggleButtonLookAndFeel::backgroundColour, UIUtils::slotBackgroundColour);
  80. _defaultPathsButton->setColour(UIUtils::ToggleButtonLookAndFeel::highlightColour, UIUtils::highlightColour);
  81. _defaultPathsButton->setColour(UIUtils::ToggleButtonLookAndFeel::disabledColour, UIUtils::deactivatedColour);
  82. _defaultPathsButton->setToggleState(defaultPathsEnabled, juce::NotificationType::dontSendNotification);
  83. _defaultPathsButton->onClick = [&]() {
  84. defaultPathsEnabled = !defaultPathsEnabled;
  85. _defaultPathsButton->setToggleState(defaultPathsEnabled, juce::NotificationType::dontSendNotification);
  86. _defaultPathsListLabel->setColour(juce::Label::textColourId, stateToLabelColour(defaultPathsEnabled));
  87. };
  88. _customPathsListComponent.reset(new CustomPathsList(customPaths));
  89. addAndMakeVisible(_customPathsListComponent.get());
  90. _customPathsButton.reset(new juce::TextButton(formatName + " Custom Paths Button"));
  91. addAndMakeVisible(_customPathsButton.get());
  92. _customPathsButton->setButtonText(TRANS("Add Custom " + formatName + " Paths"));
  93. _customPathsButton->setLookAndFeel(&_staticButtonLookAndFeel);
  94. _customPathsButton->setColour(UIUtils::StaticButtonLookAndFeel::backgroundColour, UIUtils::slotBackgroundColour);
  95. _customPathsButton->setColour(UIUtils::StaticButtonLookAndFeel::highlightColour, UIUtils::highlightColour);
  96. _customPathsButton->setColour(UIUtils::StaticButtonLookAndFeel::disabledColour, UIUtils::deactivatedColour);
  97. _customPathsButton->onClick = [&, formatName]() {
  98. const int flags {juce::FileBrowserComponent::canSelectDirectories | juce::FileBrowserComponent::openMode | juce::FileBrowserComponent::canSelectMultipleItems};
  99. _fileChooser.reset(new juce::FileChooser("Add " + formatName + " Directories"));
  100. #if _WIN32
  101. // Workaround on windows to stop the file chooser from appearing behind the plugin selector window
  102. getTopLevelComponent()->setAlwaysOnTop(false);
  103. #endif
  104. _fileChooser->launchAsync(flags, [&](const juce::FileChooser& chooser) {
  105. for (juce::File selectedDirectory : chooser.getResults()) {
  106. customPaths.addIfNotAlreadyThere(selectedDirectory);
  107. }
  108. customPaths.removeNonExistentPaths();
  109. _customPathsListComponent->rebuild();
  110. resized();
  111. #if _WIN32
  112. // Other half of the workaround
  113. // Restore the always on top state of the plugin selector window after the file chooser has closed
  114. getTopLevelComponent()->setAlwaysOnTop(true);
  115. #endif
  116. });
  117. };
  118. }
  119. FormatConfigureComponent::~FormatConfigureComponent() {
  120. _defaultPathsButton->setLookAndFeel(nullptr);
  121. _defaultPathsListLabel->setLookAndFeel(nullptr);
  122. _customPathsButton->setLookAndFeel(nullptr);
  123. }
  124. void FormatConfigureComponent::resized() {
  125. constexpr int BUTTON_WIDTH {180};
  126. constexpr int BUTTON_HEIGHT {24};
  127. constexpr int MARGIN {5};
  128. juce::Rectangle<int> availableArea = getLocalBounds();
  129. juce::Rectangle<int> defaultArea = availableArea.removeFromLeft(availableArea.getWidth() / 2).reduced(MARGIN);
  130. _defaultPathsButton->setBounds(defaultArea.removeFromTop(BUTTON_HEIGHT).withSizeKeepingCentre(BUTTON_WIDTH, BUTTON_HEIGHT));
  131. const int defaultPathsHeight {getHeightForLabelText(_defaultPathsListLabel->getText())};
  132. defaultArea.removeFromTop(TEXT_HEIGHT);
  133. _defaultPathsListLabel->setBounds(defaultArea.removeFromTop(defaultPathsHeight));
  134. availableArea.reduced(MARGIN);
  135. _customPathsButton->setBounds(availableArea.removeFromTop(BUTTON_HEIGHT).withSizeKeepingCentre(BUTTON_WIDTH, BUTTON_HEIGHT));
  136. const int customPathsHeight {_customPathsListComponent->getRequiredHeight()};
  137. availableArea.removeFromTop(TEXT_HEIGHT);
  138. _customPathsListComponent->setBounds(availableArea.removeFromTop(customPathsHeight));
  139. }
  140. ConfigurePopover::ConfigurePopover(ScanConfiguration& config, std::function<void()> onCloseCallback) :
  141. _onCloseCallback(onCloseCallback) {
  142. _vstConfigure.reset(new FormatConfigureComponent(
  143. &config.vstFormat,
  144. config.VSTDefaultPaths,
  145. config.customVSTPaths));
  146. addAndMakeVisible(_vstConfigure.get());
  147. _vst3Configure.reset(new FormatConfigureComponent(
  148. &config.vst3Format,
  149. config.VST3DefaultPaths,
  150. config.customVST3Paths));
  151. addAndMakeVisible(_vst3Configure.get());
  152. _okButton.reset(new juce::TextButton("OK button"));
  153. addAndMakeVisible(_okButton.get());
  154. _okButton->setButtonText(TRANS("OK"));
  155. _okButton->setLookAndFeel(&_buttonLookAndFeel);
  156. _okButton->setColour(UIUtils::StaticButtonLookAndFeel::backgroundColour, UIUtils::slotBackgroundColour);
  157. _okButton->setColour(UIUtils::StaticButtonLookAndFeel::highlightColour, UIUtils::highlightColour);
  158. _okButton->setColour(UIUtils::StaticButtonLookAndFeel::disabledColour, UIUtils::deactivatedColour);
  159. _okButton->onClick = [&]() { _onCloseCallback(); };
  160. _tooltipLabel.reset(new juce::Label("Tooltip Label", ""));
  161. addAndMakeVisible(_tooltipLabel.get());
  162. _tooltipLabel->setFont(juce::Font(15.00f, juce::Font::plain).withTypefaceStyle("Regular"));
  163. _tooltipLabel->setJustificationType(juce::Justification::centred);
  164. _tooltipLabel->setEditable(false, false, false);
  165. _tooltipLabel->setColour(juce::Label::textColourId, UIUtils::tooltipColour);
  166. // Start tooltip label
  167. _vstConfigure->addMouseListener(this, true);
  168. _vst3Configure->addMouseListener(this, true);
  169. }
  170. ConfigurePopover::~ConfigurePopover() {
  171. _okButton->setLookAndFeel(nullptr);
  172. }
  173. void ConfigurePopover::resized() {
  174. constexpr int WINDOW_PADDING {20};
  175. constexpr int AREA_PADDING {5};
  176. juce::Rectangle<int> availableArea = getLocalBounds().reduced(WINDOW_PADDING);
  177. _tooltipLabel->setBounds(availableArea.removeFromBottom(16));
  178. juce::Rectangle<int> okButtonArea = availableArea.removeFromBottom(availableArea.getHeight() / 4);
  179. _okButton->setBounds(okButtonArea.withSizeKeepingCentre(60, 40));
  180. _vstConfigure->setBounds(availableArea.removeFromTop(availableArea.getHeight() / 2).reduced(AREA_PADDING));
  181. _vst3Configure->setBounds(availableArea.reduced(AREA_PADDING));
  182. }
  183. void ConfigurePopover::paint(juce::Graphics& g) {
  184. g.fillAll(juce::Colours::black.withAlpha(0.8f));
  185. }
  186. void ConfigurePopover::mouseEnter(const juce::MouseEvent& event) {
  187. juce::TooltipClient* tooltipClient = dynamic_cast<juce::TooltipClient*>(event.eventComponent);
  188. if (tooltipClient != nullptr) {
  189. const juce::String displayString = tooltipClient->getTooltip();
  190. _tooltipLabel->setText(displayString, juce::dontSendNotification);
  191. }
  192. }
  193. void ConfigurePopover::mouseExit(const juce::MouseEvent& /*event*/) {
  194. if (_tooltipLabel != nullptr) {
  195. _tooltipLabel->setText("", juce::dontSendNotification);
  196. }
  197. }