void MainHostWindow::filesDropped (const StringArray& files, int x, int y) { if (files.size() == 1 && File (files[0]).hasFileExtension (filenameSuffix)) { GraphDocumentComponent* const graphEditor = getGraphEditor(); if (graphEditor != 0 && graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) { graphEditor->graph.loadFrom (File (files[0]), true); } } else { OwnedArray <PluginDescription> typesFound; knownPluginList.scanAndAddDragAndDroppedFiles (files, typesFound); GraphDocumentComponent* const graphEditor = getGraphEditor(); if (graphEditor != 0) relativePositionToOtherComponent (graphEditor, x, y); for (int i = 0; i < jmin (5, typesFound.size()); ++i) createPlugin (typesFound.getUnchecked(i), x, y); } }
bool MainHostWindow::tryToQuitApplication() { if (getGraphEditor() != 0 && getGraphEditor()->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) { JUCEApplication::quit(); return true; } return false; }
bool MainHostWindow::tryToQuitApplication() { PluginWindow::closeAllCurrentlyOpenWindows(); if (getGraphEditor() == nullptr || getGraphEditor()->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) { JUCEApplication::quit(); return true; } return false; }
void MainHostWindow::createPlugin (const PluginDescription* desc, int x, int y) { GraphDocumentComponent* const graphEditor = getGraphEditor(); if (graphEditor != nullptr) graphEditor->createNewPlugin (desc, x, y); }
void MainHostWindow::showAudioSettings() { AudioDeviceSelectorComponent audioSettingsComp (deviceManager, 0, 256, 0, 256, true, true, true, false); audioSettingsComp.setSize (500, 450); DialogWindow::showModalDialog (T("Audio Settings"), &audioSettingsComp, this, Colours::azure, true); XmlElement* const audioState = deviceManager.createStateXml(); ApplicationProperties::getInstance()->getUserSettings() ->setValue (T("audioDeviceState"), audioState); delete audioState; ApplicationProperties::getInstance()->getUserSettings()->saveIfNeeded(); GraphDocumentComponent* const graphEditor = getGraphEditor(); if (graphEditor != 0) graphEditor->graph.removeIllegalConnections(); }
void NodeComponent::mouseUp (const MouseEvent& e) { if (e.mouseWasClicked() && e.getNumberOfClicks() == 2) { if (const AudioProcessorGraph::Node::Ptr f = audioEngine.getDoc().getNodeForId (nodeID)) { AudioProcessor* const processor = f->getProcessor(); if(!InternalPluginFormat::isInternalFormat(processor->getName())) { if (PluginWindow* const w = PluginWindow::getWindowFor (f, PluginWindow::Generic/*Normal*/)) w->toFront (true); } } } else if (! e.mouseWasClicked()) { audioEngine.getDoc().setChangedFlag (true); if (moving) { moving = false; audioEngine.getDoc().beginTransaction(); audioEngine.getDoc().perform(new MoveNodeAction(audioEngine, *getGraphEditor(), nodeID, startPos, endPos), "move node"); } } }
void MainHostWindow::showAudioSettings() { AudioDeviceSelectorComponent audioSettingsComp (deviceManager, 0, 256, 0, 256, true, true, true, false); audioSettingsComp.setSize (500, 450); DialogWindow::LaunchOptions o; o.content.setNonOwned (&audioSettingsComp); o.dialogTitle = "Audio Settings"; o.componentToCentreAround = this; o.dialogBackgroundColour = Colours::azure; o.escapeKeyTriggersCloseButton = true; o.useNativeTitleBar = false; o.resizable = false; o.runModal(); ScopedPointer<XmlElement> audioState (deviceManager.createStateXml()); appProperties->getUserSettings()->setValue ("audioDeviceState", audioState); appProperties->getUserSettings()->saveIfNeeded(); GraphDocumentComponent* const graphEditor = getGraphEditor(); if (graphEditor != nullptr) graphEditor->graph.removeIllegalConnections(); }
AudioProcessorGraph* FilterIOConfigurationWindow::getGraph() const { if (auto* graphEditor = getGraphEditor()) if (auto* panel = graphEditor->graph.get()) return &panel->graph; return nullptr; }
void PinComponent::mouseDown (const MouseEvent& e) { getGraphEditor()->beginConnectorDrag (isInput ? 0 : nodeID, index, isInput ? nodeID : 0, index, e); }
void FilterIOConfigurationWindow::update() { auto nodeID = getNodeID(); if (auto* graph = getGraph()) if (nodeID != AudioProcessorGraph::NodeID()) graph->disconnectNode (nodeID); if (auto* graphEditor = getGraphEditor()) if (auto* panel = graphEditor->graphPanel.get()) panel->updateComponents(); }
bool MainHostWindow::perform (const InvocationInfo& info) { GraphDocumentComponent* const graphEditor = getGraphEditor(); switch (info.commandID) { case CommandIDs::open: if (graphEditor != 0 && graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) graphEditor->graph.loadFromUserSpecifiedFile (true); break; case CommandIDs::save: if (graphEditor != 0) graphEditor->graph.save (true, true); break; case CommandIDs::saveAs: if (graphEditor != 0) graphEditor->graph.saveAs (File::nonexistent, true, true, true); break; case CommandIDs::showPluginListEditor: if (PluginListWindow::currentPluginListWindow == 0) PluginListWindow::currentPluginListWindow = new PluginListWindow (knownPluginList); PluginListWindow::currentPluginListWindow->toFront (true); break; case CommandIDs::showAudioSettings: showAudioSettings(); break; case CommandIDs::aboutBox: { /* AboutBoxComponent aboutComp; DialogWindow::showModalDialog (T("About"), &aboutComp, this, Colours::white, true, false, false); */ } break; default: return false; } return true; }
void ConnectorComponent::mouseDrag (const MouseEvent& e) { if ((! dragging) && ! e.mouseWasClicked()) { dragging = true; audioEngine.getDoc().removeConnection (sourceNodeId, sourceNodeChannel, destNodeId, destNodeChannel); double distanceFromStart, distanceFromEnd; getDistancesFromEnds (e.x, e.y, distanceFromStart, distanceFromEnd); const bool isNearerSource = (distanceFromStart < distanceFromEnd); getGraphEditor()->beginConnectorDrag (isNearerSource ? 0 : sourceNodeId, sourceNodeChannel, isNearerSource ? destNodeId : 0, destNodeChannel, e); } else if (dragging) { getGraphEditor()->dragConnector (e); } }
void ConnectorComponent::getPoints (float& x1, float& y1, float& x2, float& y2) const { x1 = lastInputX; y1 = lastInputY; x2 = lastOutputX; y2 = lastOutputY; if (GraphEditor* const hostPanel = getGraphEditor()) { if (NodeComponent* srcNodeComp = hostPanel->getComponentForNode (sourceNodeId)) srcNodeComp->getPinPos (sourceNodeChannel, false, x1, y1); if (NodeComponent* dstNodeComp = hostPanel->getComponentForNode (destNodeId)) dstNodeComp->getPinPos (destNodeChannel, true, x2, y2); } }
void NodeComponent::mouseDrag (const MouseEvent& e) { if (! e.mods.isPopupMenu()) { Point<int> pos (originalPos + Point<int> (e.getDistanceFromDragStartX(), e.getDistanceFromDragStartY())); if (getParentComponent() != nullptr) pos = getParentComponent()->getLocalPoint (nullptr, pos); endPos.x = (pos.getX() + getWidth() / 2) / (double) getParentWidth(); endPos.y = (pos.getY() + getHeight() / 2) / (double) getParentHeight(); audioEngine.getDoc().setNodePosition (nodeID, endPos.x, endPos.y); getGraphEditor()->updateComponents(); } }
bool MainHostWindow::perform (const InvocationInfo& info) { GraphDocumentComponent* const graphEditor = getGraphEditor(); switch (info.commandID) { case CommandIDs::open: if (graphEditor != nullptr && graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) graphEditor->graph.loadFromUserSpecifiedFile (true); break; case CommandIDs::save: if (graphEditor != nullptr) graphEditor->graph.save (true, true); break; case CommandIDs::saveAs: if (graphEditor != nullptr) graphEditor->graph.saveAs (File::nonexistent, true, true, true); break; case CommandIDs::showPluginListEditor: if (pluginListWindow == nullptr) pluginListWindow = new PluginListWindow (*this, formatManager); pluginListWindow->toFront (true); break; case CommandIDs::showAudioSettings: showAudioSettings(); break; case CommandIDs::aboutBox: // TODO break; default: return false; } return true; }
void MainHostWindow::menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/) { GraphDocumentComponent* const graphEditor = getGraphEditor(); if (menuItemID == 250) { if (graphEditor != 0) graphEditor->graph.clear(); } else if (menuItemID >= 100 && menuItemID < 200) { RecentlyOpenedFilesList recentFiles; recentFiles.restoreFromString (ApplicationProperties::getInstance()->getUserSettings() ->getValue ("recentFilterGraphFiles")); if (graphEditor != 0 && graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) graphEditor->graph.loadFrom (recentFiles.getFile (menuItemID - 100), true); } else if (menuItemID >= 200 && menuItemID < 210) { if (menuItemID == 200) pluginSortMethod = KnownPluginList::defaultOrder; else if (menuItemID == 201) pluginSortMethod = KnownPluginList::sortAlphabetically; else if (menuItemID == 202) pluginSortMethod = KnownPluginList::sortByCategory; else if (menuItemID == 203) pluginSortMethod = KnownPluginList::sortByManufacturer; else if (menuItemID == 204) pluginSortMethod = KnownPluginList::sortByFileSystemLocation; ApplicationProperties::getInstance()->getUserSettings() ->setValue (T("pluginSortMethod"), (int) pluginSortMethod); } else { createPlugin (getChosenType (menuItemID), proportionOfWidth (0.3f + Random::getSystemRandom().nextFloat() * 0.6f), proportionOfHeight (0.3f + Random::getSystemRandom().nextFloat() * 0.6f)); } }
void NodeComponent::paint (Graphics& g) { g.setColour (Colours::lightgrey); if (highlight) g.setColour (Colours::white); const int x = 4; const int y = pinSize; const int w = getWidth() - x * 2; const int h = getHeight() - pinSize * 2; g.fillRect(x, y, w, h); g.setColour (Colours::black); if (getGraphEditor()->getLassoSelection().isSelected(this)) g.setColour (Colours::black); else g.setColour (Colours::grey); g.drawRoundedRectangle(x, y, w, h, 2, 1); }
void MainHostWindow::filesDropped (const StringArray& files, int x, int y) { GraphDocumentComponent* const graphEditor = getGraphEditor(); if (graphEditor != nullptr) { if (files.size() == 1 && File (files[0]).hasFileExtension (filenameSuffix)) { if (graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) graphEditor->graph.loadFrom (File (files[0]), true); } else { OwnedArray <PluginDescription> typesFound; knownPluginList.scanAndAddDragAndDroppedFiles (formatManager, files, typesFound); Point<int> pos (graphEditor->getLocalPoint (this, Point<int> (x, y))); for (int i = 0; i < jmin (5, typesFound.size()); ++i) createPlugin (typesFound.getUnchecked(i), pos.getX(), pos.getY()); } } }
void NodeComponent::mouseDown (const MouseEvent& e) { originalPos = localPointToGlobal (Point<int>()); toFront (true); if (e.mods.isPopupMenu()) { PopupMenu m; m.addItem (1, TRANS("Delete this node")); m.addItem (2, TRANS("Disconnect all pins")); if (AudioProcessorGraph::Node::Ptr f = audioEngine.getDoc().getNodeForId (nodeID)) { AudioProcessor* const processor = f->getProcessor(); jassert (processor != nullptr); if(!InternalPluginFormat::isInternalFormat(processor->getName())) { bool hasParams = (processor->getNumParameters() > 0); m.addItem (3, TRANS("Add a pMix Preset"), hasParams); m.addItem (4, TRANS("Set pMix Colour"), hasParams); m.addItem (5, TRANS("Interpolate all Parameters"), hasParams); m.addItem (6, TRANS("Clear all Parameters"), hasParams); m.addSeparator(); int uiStatus = f->properties["uiStatus"]; PopupMenu ui; ui.addItem (7, TRANS("Disabled"), true, uiStatus == kUIStatusNone); ui.addItem (8, TRANS("Embedded"), true, uiStatus == kUIStatusEmbed); // ui.addItem (9, TRANS("Floating"), true, uiStatus == kUIStatusFloating); m.addSubMenu (TRANS("Set UI Mode"), ui); } } const int r = m.show(); if (r == 1) { if (AudioProcessorGraph::Node::Ptr f = audioEngine.getDoc().getNodeForId (nodeID)) { AudioPluginInstance* const instance = dynamic_cast<AudioPluginInstance*>(f->getProcessor()); if (instance) { removeEditor(); audioEngine.getDoc().beginTransaction(); audioEngine.getDoc().perform(new RemoveNodeAction(audioEngine, *getGraphEditor(), nodeID), TRANS("remove node")); getGraphEditor()->clearSelection(); } } return; } else if (r == 2) { audioEngine.getDoc().disconnectNode (nodeID); } else if (r == 3) { Random rand; audioEngine.getDoc().addPreset(nodeID, rand.nextFloat(), rand.nextFloat()); } else if (r == 4) { ColourSelector* colourSelector = new ColourSelector(ColourSelector::showSliders|ColourSelector::showColourAtTop|ColourSelector::showColourspace); colourSelector->setName ("background"); colourSelector->setCurrentColour (audioEngine.getDoc().getNodeColour(nodeID)); colourSelector->addChangeListener (this); colourSelector->setColour (ColourSelector::backgroundColourId, Colours::lightgrey); colourSelector->setSize (300, 400); CallOutBox::launchAsynchronously (colourSelector, getScreenBounds(), nullptr); } else if (r == 5 || r == 6) { if (AudioProcessorGraph::Node::Ptr f = audioEngine.getDoc().getNodeForId (nodeID)) { for (int p=0; p < f->getProcessor()->getNumParameters(); p++) { audioEngine.getDoc().setParameterToInterpolate(nodeID, p, r==5); } repaint(); } } else if (r == 7) { audioEngine.getDoc().setNodeUIStatus(nodeID, kUIStatusNone); removeEditor(); PluginWindow::closeCurrentlyOpenWindowsFor(nodeID); update(); } else if (r == 8) { audioEngine.getDoc().setNodeUIStatus(nodeID, kUIStatusEmbed); PluginWindow::closeCurrentlyOpenWindowsFor(nodeID); update(); } // else if (r == 9) // { // if (AudioProcessorGraph::Node::Ptr f = audioEngine.getDoc().getNodeForId (nodeID)) // { // AudioProcessor* const processor = f->getProcessor(); // jassert (processor != nullptr); // // String name = processor->getName(); // // if (r > 0) // { // removeEditor(); // // PluginWindow::WindowFormatType type = processor->hasEditor() ? PluginWindow::Normal : PluginWindow::Generic; // // if (PluginWindow* const w = PluginWindow::getWindowFor (f, type)) // w->toFront (true); // // audioEngine.getDoc().setNodeUIStatus(nodeID, kUIStatusFloating); // update(); // }; // } // } } else { moving = true; getGraphEditor()->getLassoSelection().selectOnly(this); audioEngine.getDoc().getNodePosition(nodeID, startPos.x, startPos.y); } }
void PinComponent::mouseUp (const MouseEvent& e) { getGraphEditor()->endDraggingConnector (e); }
void PinComponent::mouseDrag (const MouseEvent& e) { getGraphEditor()->dragConnector (e); }
void ConnectorComponent::mouseUp (const MouseEvent& e) { if (dragging) getGraphEditor()->endDraggingConnector (e); }
BlockPropertiesPanel::BlockPropertiesPanel(GraphBlock *block, QWidget *parent): QWidget(parent), _ignoreChanges(true), _idLabel(new QLabel(this)), _idLineEdit(new QLineEdit(this)), _affinityZoneLabel(new QLabel(this)), _affinityZoneBox(nullptr), _blockErrorLabel(new QLabel(this)), _updateTimer(new QTimer(this)), _formLayout(nullptr), _block(block) { auto blockDesc = block->getBlockDesc(); //master layout for this widget auto layout = new QVBoxLayout(this); //create a scroller and a form layout auto scroll = new QScrollArea(this); scroll->setWidgetResizable(true); scroll->setWidget(new QWidget(scroll)); _formLayout = new QFormLayout(scroll); scroll->widget()->setLayout(_formLayout); layout->addWidget(scroll); //title { auto label = new QLabel(QString("<h1>%1</h1>").arg(_block->getTitle().toHtmlEscaped()), this); label->setAlignment(Qt::AlignCenter); _formLayout->addRow(label); } //errors { _formLayout->addRow(_blockErrorLabel); } //id { _idOriginal = _block->getId(); _formLayout->addRow(_idLabel, _idLineEdit); connect(_idLineEdit, SIGNAL(textEdited(const QString &)), this, SLOT(handleEditWidgetChanged(const QString &))); connect(_idLineEdit, SIGNAL(returnPressed(void)), this, SLOT(handleCommitButton(void))); } //properties for (const auto &prop : _block->getProperties()) { _propIdToOriginal[prop.getKey()] = _block->getPropertyValue(prop.getKey()); auto paramDesc = _block->getParamDesc(prop.getKey()); assert(paramDesc); //create editable widget auto editWidget = new BlockPropertyEditWidget(paramDesc, this); connect(editWidget, SIGNAL(valueChanged(void)), this, SLOT(handleEditWidgetChanged(void))); connect(editWidget, SIGNAL(commitRequested(void)), this, SLOT(handleCommitButton(void))); _propIdToEditWidget[prop.getKey()] = editWidget; //create labels _propIdToFormLabel[prop.getKey()] = new QLabel(this); _propIdToErrorLabel[prop.getKey()] = new QLabel(this); editWidget->setToolTip(this->getParamDocString(_block->getParamDesc(prop.getKey()))); //layout stuff auto editLayout = new QVBoxLayout(); editLayout->addWidget(editWidget); editLayout->addWidget(_propIdToErrorLabel[prop.getKey()]); _formLayout->addRow(_propIdToFormLabel[prop.getKey()], editLayout); } //affinity zone { _affinityZoneOriginal = _block->getAffinityZone(); auto dock = dynamic_cast<AffinityZonesDock *>(getObjectMap()["affinityZonesDock"]); assert(dock != nullptr); _affinityZoneBox = dock->makeComboBox(this); _formLayout->addRow(_affinityZoneLabel, _affinityZoneBox); connect(_affinityZoneBox, SIGNAL(activated(const QString &)), this, SLOT(handleEditWidgetChanged(const QString &))); } //draw the block's preview onto a mini pixmap //this is cool, maybe useful, but its big, where can we put it? /* { const auto bounds = _block->getBoundingRect(); QPixmap pixmap(bounds.size().toSize()+QSize(2,2)); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.translate(-bounds.topLeft()+QPoint(1,1)); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::HighQualityAntialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); _block->render(painter); painter.end(); auto label = new QLabel(this); label->setPixmap(pixmap); _formLayout->addRow(label); _formLayout->setAlignment(label, Qt::AlignHCenter); } */ //block level description if (blockDesc->isArray("docs")) { QString output; output += QString("<h1>%1</h1>").arg(QString::fromStdString(blockDesc->get("name").convert<std::string>())); output += QString("<p>%1</p>").arg(QString::fromStdString(block->getBlockDescPath())); output += "<p>"; for (const auto &lineObj : *blockDesc->getArray("docs")) { const auto line = lineObj.extract<std::string>(); if (line.empty()) output += "<p /><p>"; else output += QString::fromStdString(line)+"\n"; } output += "</p>"; //enumerate properties if (not _block->getProperties().empty()) { output += QString("<h2>%1</h2>").arg(tr("Properties")); for (const auto &prop : _block->getProperties()) { output += this->getParamDocString(_block->getParamDesc(prop.getKey())); } } //enumerate slots if (not block->getSlotPorts().empty()) { output += QString("<h2>%1</h2>").arg(tr("Slots")); output += "<ul>"; for (const auto &port : block->getSlotPorts()) { output += QString("<li>%1(...)</li>").arg(port.getName()); } output += "</ul>"; } //enumerate signals if (not block->getSignalPorts().empty()) { output += QString("<h2>%1</h2>").arg(tr("Signals")); output += "<ul>"; for (const auto &port : block->getSignalPorts()) { output += QString("<li>%1(...)</li>").arg(port.getName()); } output += "</ul>"; } auto text = new QLabel(output, this); text->setStyleSheet("QLabel{background:white;margin:1px;}"); text->setWordWrap(true); _formLayout->addRow(text); } //buttons { auto buttonLayout = new QHBoxLayout(); layout->addLayout(buttonLayout); auto commitButton = new QPushButton(makeIconFromTheme("dialog-ok-apply"), tr("Commit"), this); connect(commitButton, SIGNAL(pressed(void)), this, SLOT(handleCommitButton(void))); buttonLayout->addWidget(commitButton); auto cancelButton = new QPushButton(makeIconFromTheme("dialog-cancel"), tr("Cancel"), this); connect(cancelButton, SIGNAL(pressed(void)), this, SLOT(handleCancelButton(void))); buttonLayout->addWidget(cancelButton); } //update timer _updateTimer->setSingleShot(true); _updateTimer->setInterval(UPDATE_TIMER_MS); connect(_updateTimer, SIGNAL(timeout(void)), this, SLOT(handleUpdateTimerExpired(void))); //connect state change to the graph editor auto draw = dynamic_cast<GraphDraw *>(_block->parent()); auto editor = draw->getGraphEditor(); connect(this, SIGNAL(stateChanged(const GraphState &)), editor, SLOT(handleStateChange(const GraphState &))); connect(_block, SIGNAL(destroyed(QObject*)), this, SLOT(handleBlockDestroyed(QObject*))); this->updateAllForms(); _ignoreChanges = false; }