#include "PluginSearchPathEditor.hpp" using namespace juce; static std::unique_ptr vecToXml(const std::string & elemName, const std::vector & v) { auto elem = std::make_unique(juce::String(elemName)); for(auto & s : v) { auto childElem = std::make_unique("Elem"); childElem->setAttribute("v", s); elem->addChildElement(childElem.release()); } return elem; } std::unique_ptr SearchPathSettings::toXml() const { auto elem = std::make_unique("SearchPathSettings"); elem->setAttribute("useVstDefaultSearchPaths", useVstDefaultSearchPaths); elem->setAttribute("useVst3DefaultSearchPaths", useVst3DefaultSearchPaths); elem->addChildElement(vecToXml("vstSearchPaths", vstSearchPaths).release()); elem->addChildElement(vecToXml("vst3SearchPaths", vst3SearchPaths).release()); return elem; } void SearchPathSettings::fromXml(XmlElement* elem) { useVstDefaultSearchPaths = elem->getBoolAttribute("useVstDefaultSearchPaths"); useVst3DefaultSearchPaths = elem->getBoolAttribute("useVstDefaultSearchPaths"); vstSearchPaths.clear(); vst3SearchPaths.clear(); for(auto * childElem : elem->getChildIterator()) { auto & dest = (childElem->getTagName() == "vstSearchPaths") ? vstSearchPaths : vst3SearchPaths; for(auto * grandchildElem : childElem->getChildIterator()) { dest.push_back(grandchildElem->getStringAttribute("v").toStdString()); } } } class SearchPathListModel final : public Component, public ListBoxModel { public: SearchPathListModel(const std::vector & paths) : paths(paths), lastRowSelected(-1) { } ~SearchPathListModel() { } int getNumRows() override { return (int)paths.size(); } void paintListBoxItem(int rowNumber, Graphics& g, int width, int height, bool rowIsSelected) override { if(rowNumber < 0 || rowNumber >= paths.size()) { return; } if(rowIsSelected) { g.fillAll(Colours::mediumblue); } g.setColour(Colours::lightgrey); g.drawText(paths[rowNumber], 4, 0, width - 4, height, Justification::left, true); } void selectedRowsChanged(int lastRowSelectedIn) override { lastRowSelected = lastRowSelectedIn; } const std::vector & paths; int lastRowSelected; }; PluginSearchPathEditor::PluginSearchPathEditor(SearchPathSettings & settings, std::function closedHandler, std::function settingsEditedHandler) : DocumentWindow ("Edit Plugin Search Paths", LookAndFeel::getDefaultLookAndFeel().findColour (ResizableWindow::backgroundColourId), DocumentWindow::minimiseButton | DocumentWindow::closeButton), closedHandler(std::move(closedHandler)), settingsEditedHandler(std::move(settingsEditedHandler)), settings(settings) { setContentOwned(new PluginSearchPathEditorContent(*this), false); setUsingNativeTitleBar(true); setResizable(false, false); setSize(600, 380); auto primaryDisplay = Desktop::getInstance().getDisplays().getPrimaryDisplay(); if(primaryDisplay) { auto r = primaryDisplay->userArea; setTopLeftPosition((r.getWidth() - getWidth()) / 2, (r.getHeight() - getHeight()) / 2); } else { setTopLeftPosition(20, 20); } setOpaque(true); setVisible(true); toFront(false); } PluginSearchPathEditor::~PluginSearchPathEditor() { } void PluginSearchPathEditor::closeButtonPressed() { closedHandler(); } void PluginSearchPathEditor::edited() { settingsEditedHandler(); } SearchPathEditorWidget::SearchPathEditorWidget(std::vector & paths, std::function edited) : paths(paths), edited(edited) { listModel = std::make_unique(paths); listBox.setModel(listModel.get()); addAndMakeVisible(&listBox); addButton.setButtonText("+"); addButton.addListener(this); addAndMakeVisible(&addButton); removeButton.setButtonText("-"); removeButton.addListener(this); addAndMakeVisible(&removeButton); } SearchPathEditorWidget::~SearchPathEditorWidget() { listBox.setModel(nullptr); addButton.removeListener(this); removeButton.removeListener(this); } void SearchPathEditorWidget::resized() { listBox.setTopLeftPosition(10, 10); listBox.setSize(getWidth() - 20, getHeight() - 50); addButton.setTopLeftPosition(getWidth() - 65, getHeight() - 35); addButton.setSize(25, 25); removeButton.setTopLeftPosition(getWidth() - 35, getHeight() - 35); removeButton.setSize(25, 25); } void SearchPathEditorWidget::buttonClicked(juce::Button *b) { if(b == &addButton) { if(fileChooser) { return; } fileChooser = std::make_unique("Select search path"); fileChooser->launchAsync(FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories, [this](const FileChooser& c) { auto res = c.getResults(); if(res.size() > 0) { auto p = res[0].getFullPathName().toStdString(); for(auto & p0: paths) { if(p0 == p) { return; } } paths.push_back(res[0].getFullPathName().toStdString()); listBox.updateContent(); edited(); } fileChooser.reset(); }); } else { int rowToDelete = listModel->lastRowSelected; listModel->lastRowSelected = -1; listBox.setSelectedRows({}, NotificationType::dontSendNotification); if(rowToDelete < 0 || rowToDelete >= paths.size()) { return; } paths.erase(paths.begin() + rowToDelete); listBox.updateContent(); edited(); } } PluginSearchPathEditorContent::PluginSearchPathEditorContent(PluginSearchPathEditor & editor) : editor(editor), e_vst(editor.settings.vstSearchPaths, [this]{ edited(); }), e_vst3(editor.settings.vst3SearchPaths, [this]{ edited(); }) { l_vst.setText("VST", NotificationType::dontSendNotification); l_vst3.setText("VST3", NotificationType::dontSendNotification); d_vst.setButtonText("Include default search paths"); d_vst.setToggleState(editor.settings.useVstDefaultSearchPaths, NotificationType::dontSendNotification); d_vst.addListener(this); d_vst3.setButtonText("Include default search paths"); d_vst3.setToggleState(editor.settings.useVst3DefaultSearchPaths, NotificationType::dontSendNotification); d_vst3.addListener(this); addAndMakeVisible(&l_vst); addAndMakeVisible(&l_vst3); addAndMakeVisible(&d_vst); addAndMakeVisible(&d_vst3); addAndMakeVisible(&e_vst); addAndMakeVisible(&e_vst3); } PluginSearchPathEditorContent::~PluginSearchPathEditorContent() { d_vst.removeListener(this); d_vst3.removeListener(this); } void PluginSearchPathEditorContent::resized() { l_vst.setTopLeftPosition(10, 10); l_vst.setSize(getWidth() - 20, 20); d_vst.setTopLeftPosition(100, 10); d_vst.setSize(getWidth() - 100, 20); e_vst.setTopLeftPosition(10, 30); e_vst.setSize(getWidth() - 20, 150); l_vst3.setTopLeftPosition(10, 200); l_vst3.setSize(getWidth() - 20, 20); d_vst3.setTopLeftPosition(100, 200); d_vst3.setSize(getWidth() - 100, 20); e_vst3.setTopLeftPosition(10, 220); e_vst3.setSize(getWidth() - 20, 150); } void PluginSearchPathEditorContent::edited() { editor.edited(); } void PluginSearchPathEditorContent::buttonClicked(juce::Button *b) { editor.settings.useVstDefaultSearchPaths = d_vst.getToggleState(); editor.settings.useVst3DefaultSearchPaths = d_vst3.getToggleState(); edited(); }