void GraphScene::init(InitType initType) { // Remove all nodes from the scene (and thus also connecting edges) for (int row = 0; row < m_gridLayout->rowCount(); row++) { for (int column = 0; column < m_gridLayout->columnCount(); column++) { // If there is a node in that cell of the grid layout, remove it removeItem(static_cast<NodeItem *>(m_gridLayout->itemAt(row, column))); } } switch(initType) { // Check how to init the scene case EmptyInit: setInputNode(NULL); // Reset input/output nodes setOuputNode(NULL); break; case StandardInit: NodeItem *n1 = new NodeItem(NULL, this); // Create default input/output nodes n1->setName("1"); m_gridLayout->addItem(n1, 0, 0); NodeItem *n2 = new NodeItem(NULL, this); n2->setName("2"); m_gridLayout->addItem(n2, 0, 1); addEdge(n1, n2); // and wire them with an edge setInputNode(n1); // Set default input/output nodes setOuputNode(n2); break; } setSceneRect(QRectF()); emit graphChanged(); }
bool GraphComponent::closeSelectedPlugins () { DBG ("GraphComponent::closeSelectedPlugins"); jassert (host != 0); if (selectedNodes.getNumSelected () > 0) { for (int i = 0; i < selectedNodes.getNumSelected (); i++) { GraphNodeComponent* selected = selectedNodes.getSelectedItem (i); BasePlugin* plugin = (BasePlugin*) selected->getUserData (); if (plugin) { if (owner->isPluginEditorWindowOpen (plugin)) owner->closePluginEditorWindow (plugin); host->closePlugin (plugin); selectedNodes.deselect (selected); deletePluginNode (selected); } } selectedNodes.deselectAll (); graphChanged (); return true; } return false; }
void GraphView::setGraph( qan::Graph* graph ) { if ( graph == nullptr ) { qDebug() << "qan::GraphView::setGraph(): Error: Setting a nullptr graph in Qan.GraphView is not supported."; return; } _graph = graph; _graph->setContainerItem( getContainerItem() ); emit graphChanged(); }
bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice) { K_XT(AudioOutput); if (!xt->m_xine) { // remember the choice until we have a xine_t m_device = newDevice; return true; } xine_audio_port_t *port = createPort(newDevice); if (!port) { debug() << Q_FUNC_INFO << "new audio port is invalid"; return false; } KeepReference<> *keep = new KeepReference<>; keep->addObject(xt); keep->ready(); AudioOutputXT *newXt = new AudioOutputXT; newXt->m_audioPort = port; newXt->m_xine = xt->m_xine; m_threadSafeObject = newXt; m_device = newDevice; SourceNode *src = source(); if (src) { QList<WireCall> wireCall; QList<WireCall> unwireCall; wireCall << WireCall(src, this); unwireCall << WireCall(src, QExplicitlySharedDataPointer<SinkNodeXT>(xt)); QCoreApplication::postEvent(XineThread::instance(), new RewireEvent(wireCall, unwireCall)); graphChanged(); } AudioDataOutputXT *dataOutput = dynamic_cast<AudioDataOutputXT*>(m_source->threadSafeObject().data()); if (dataOutput) dataOutput->intercept(xt->m_audioPort); return true; }
bool GraphScene::loadFrom(const QString &fileName) { QFile file(fileName); if (file.exists() && file.open(QFile::ReadOnly)) { QTextStream stream(&file); QHash<QString, NodeItem *> nodes; // Temporary hashmap for faster lookup init(EmptyInit); // Create an empty scene QString line; do { // Iterate over all the lines in the file line = stream.readLine(); // and split the line at ' ' characters const QStringList splittedLine = line.split(" "); if (splittedLine[0] == "node") { // Found a node, add it to the scene NodeItem *node = new NodeItem(NULL, this); node->setName(splittedLine[1]); NodeItem::NodeType nodeType = static_cast<NodeItem::NodeType>(splittedLine[2].toInt()); switch (nodeType) { case NodeItem::InputNode: setInputNode(node); // We found the input node break; case NodeItem::OutputNode: setOuputNode(node); // We found the ouput node break; case NodeItem::StandardNode: // This should already be set by default but doesn't harm here node->setNodeType(NodeItem::StandardNode); break; } // There is obviously a (Matlab) formula attached, parse it... if (splittedLine.length() > 5) { int formulaStart = line.indexOf('"'); QString formula = line; formula.remove(0, formulaStart); while (!formula.endsWith('"')) { // Formula spans multiple lines formula += '\n' + stream.readLine(); } formula.chop(1); // Remove leading '"' formula.remove(0, 1); // Remove trailing '"' node->setFormula(formula); } nodes.insert(node->name(), node); m_gridLayout->addItem(node, splittedLine[3].toInt(), splittedLine[4].toInt()); } else if (splittedLine[0] == "edge") { NodeItem *start = nodes[splittedLine[2]]; // Found an edge, add it to the scene NodeItem *end = nodes[splittedLine[3]]; DirectedEdgeItem *edge = addEdge(start, end); edge->setName(splittedLine[1]); // There is obviously a (Matlab) formula attached, parse it... if (splittedLine.length() > 4) { int formulaStart = line.indexOf('"'); QString formula = line; formula.remove(0, formulaStart); while (!formula.endsWith('"')) { // Formula spans multiple lines formula += '\n' + stream.readLine(); } formula.chop(1); // Remove leading '"' formula.remove(0, 1); // Remove trailing '"' edge->setFormula(formula); } } } while (!line.isNull()); emit graphChanged(); file.close(); return true; } return false; }
bool QNodeGraph::eventFilter(QObject *o, QEvent *e) { QGraphicsSceneMouseEvent *me = (QGraphicsSceneMouseEvent*) e; switch ((int) e->type()) { case QEvent::KeyPress: { QKeyEvent *k = static_cast<QKeyEvent *>(e); switch(k->key()) { case Qt::Key_P: { parseGraph(); break; } case Qt::Key_X: { BaseSDFOP* op = new Mandelbulb_SDFOP(); DistanceOpNode *c = new DistanceOpNode(op, scene, 0); break; } case Qt::Key_C: { BaseSDFOP* op = new Union_SDFOP(); DistanceOpNode *c = new DistanceOpNode(op, scene, 0); break; } case Qt::Key_V: { BaseSDFOP* op = new Sphere_SDFOP(1.0); DistanceOpNode *c = new DistanceOpNode(op, scene, 0); break; } } break; } case QEvent::GraphicsSceneMousePress: { switch ((int) me->button()) { case Qt::LeftButton: { QGraphicsItem *item = itemAt(me->scenePos()); if (item && item->type() == QNEPort::Type) { conn = new QNEConnection(0); scene->addItem(conn); conn->setPort1((QNEPort*) item); conn->setPos1(item->scenePos()); conn->setPos2(me->scenePos()); conn->updatePath(); // emit graphChanged(); return true; } else if (item && item->type() == QNEBlock::Type) { /* if (selBlock) selBlock->setSelected(); */ // selBlock = (QNEBlock*) item; } break; } case Qt::RightButton: { QGraphicsItem *item = itemAt(me->scenePos()); if (item && (item->type() == QNEConnection::Type || item->type() == QNEBlock::Type)) { delete item; emit graphChanged(); } // if (selBlock == (QNEBlock*) item) // selBlock = 0; break; } } } case QEvent::GraphicsSceneMouseMove: { if (conn) { conn->setPos2(me->scenePos()); conn->updatePath(); return true; } break; } case QEvent::GraphicsSceneMouseRelease: { if (conn && me->button() == Qt::LeftButton) { QGraphicsItem *item = itemAt(me->scenePos()); if (item && item->type() == QNEPort::Type) { QNEPort *port1 = conn->port1(); QNEPort *port2 = (QNEPort*) item; if (port1->block() != port2->block() && port1->isOutput() != port2->isOutput() && !port1->isConnected(port2)) { conn->setPos2(port2->scenePos()); conn->setPort2(port2); conn->updatePath(); conn = 0; emit graphChanged(); return true; } } delete conn; conn = 0; return true; } break; } } return QObject::eventFilter(o, e); }
void GraphComponent::updateDisplayPlugins () { DBG ("GraphComponent::updateDisplayPlugins"); jassert (host != 0); cleanInternalGraph (); // rebuild nodes ! for (int i = 0; i < host->getPluginsCount (); i++) { createPluginNode (host->getPluginByIndex (i)); } // update audio / midi connection links ! ProcessingGraph* audioGraph = host->getAudioGraph (); for (int i = 0; i < audioGraph->getNodeCount (); i++) { ProcessingNode* source = audioGraph->getNode (i); BasePlugin* sourceData = (BasePlugin*) source->getData (); GraphNodeComponent* sourceNode = findNodeByUserData (sourceData); if (sourceNode != 0) { for (int j = source->getLinksCount (JOST_LINKTYPE_AUDIO); --j >= 0;) { ProcessingLink* link = source->getLink (JOST_LINKTYPE_AUDIO, j); BasePlugin* destData = (BasePlugin*) link->destination->getData (); GraphNodeComponent* destNode = findNodeByUserData (destData); if (destNode != 0) { sourceNode->connectToNode (link->sourcePort, destNode, link->destinationPort, false); } } } } for (int i = 0; i < audioGraph->getNodeCount (); i++) { ProcessingNode* source = audioGraph->getNode (i); BasePlugin* sourceData = (BasePlugin*) source->getData (); GraphNodeComponent* sourceNode = findNodeByUserData (sourceData); if (sourceNode != 0) { for (int j = source->getLinksCount (JOST_LINKTYPE_MIDI); --j >= 0;) { ProcessingLink* link = source->getLink (JOST_LINKTYPE_MIDI, j); BasePlugin* destData = (BasePlugin*) link->destination->getData (); GraphNodeComponent* destNode = findNodeByUserData (destData); if (destNode != 0) { sourceNode->connectToNode (link->sourcePort + sourceNode->getFirstOutputOfType (JOST_LINKTYPE_MIDI), destNode, link->destinationPort + destNode->getFirstInputOfType (JOST_LINKTYPE_MIDI), false); } } } } // update connectors graphChanged (); // update fixed node size and position resized (); }
void GraphComponent::nodePopupMenuSelected (GraphNodeComponent* node) { DBG ("GraphComponent::nodePopupMenuSelected"); jassert (node != 0); currentClickedNode = node; bool addFirstSeparator = false; PopupMenu menu, subMenu; BasePlugin* plugin = (BasePlugin*) node->getUserData (); if (plugin->hasEditor () || plugin->wantsEditor () || plugin->isEditorInternal ()) { menu.addItem (1, "Open editor"); addFirstSeparator = true; } if (node != inputs && node != outputs) { menu.addItem (2, "Remove " + plugin->getName()); addFirstSeparator = true; } if (addFirstSeparator) menu.addSeparator (); menu.addItem (3, "Lock", true, node->isLocked ()); // node colour.. ColourSelector colourSelector; colourSelector.setName (T("background")); colourSelector.setCurrentColour (node->getNodeColour ()); colourSelector.addChangeListener (this); subMenu.addCustomItem (1234, &colourSelector, 300, 300, false); menu.addSubMenu (T("Colour"), subMenu); menu.addSeparator (); menu.addItem (4, "Mute", true, plugin->isMuted ()); menu.addItem (5, "Bypass", true, plugin->isBypass ()); menu.addItem (6, "Solo", false, false); menu.addSeparator (); int inputLinks = node->getInputLinksCount (); int outputLinks = node->getOutputLinksCount (); if (inputLinks > 0 && outputLinks > 0) menu.addItem (7, "Disconnect all"); if (inputLinks > 0) menu.addItem (8, "Disconnect inputs"); if (outputLinks > 0) menu.addItem (9, "Disconnect outputs"); const int result = menu.show(); switch (result) { case 1: // Open editor { owner->openPluginEditorWindow (plugin); break; } case 2: // Close { if (owner->isPluginEditorWindowOpen (plugin)) owner->closePluginEditorWindow (plugin); if (plugin) { host->closePlugin (plugin); selectedNodes.deselect (node); deletePluginNode (node); graphChanged (); } break; } case 3: // Lock / unlock { bool lockedState = ! node->isLocked (); if (plugin) plugin->setValue (PROP_GRAPHLOCKED, lockedState); node->setLocked (lockedState); node->repaint (); } break; case 4: // Mute { if (plugin) plugin->setMuted (! plugin->isMuted()); } break; case 5: // Bypass { if (plugin) plugin->setBypass (! plugin->isBypass()); } break; case 6: // Solo (TODO) break; case 7: // Disconnect all node->breakAllLinks(); break; case 8: // Disconnect inputs node->breakInputLinks(); break; case 9: // Disconnect outputs node->breakOutputLinks(); break; default: break; } currentClickedNode = 0; }
void GraphComponent::nodePopupMenuSelected (GraphNodeComponent* node) { DBG ("GraphComponent::nodePopupMenuSelected"); jassert (node != 0); currentClickedNode = node; bool addFirstSeparator = false; PopupMenu menu, subMenu, synthMidiChanMenu, midiChanMenu; BasePlugin* plugin = (BasePlugin*) node->getUserData (); if (plugin->hasEditor () || plugin->wantsEditor () || plugin->isEditorInternal ()) { menu.addItem (1, "Open editor"); menu.addItem (2, "Prefer MIDI binding editor", true, plugin->getBoolValue(PROP_WINDOWPREFERGENERIC, false)); addFirstSeparator = true; } if (node != inputs && node != outputs) { menu.addItem (3, "Remove " + plugin->getName() + String(" \"") + plugin->getInstanceName() + String("\"")); addFirstSeparator = true; } if (addFirstSeparator) menu.addSeparator (); menu.addItem (4, "Lock", true, node->isLocked ()); // node colour.. ColourSelector colourSelector; colourSelector.setName (T("background")); colourSelector.setCurrentColour (node->getNodeColour ()); colourSelector.addChangeListener (this); subMenu.addCustomItem (1234, &colourSelector, 300, 300, false); menu.addSubMenu (T("Colour"), subMenu); menu.addSeparator (); menu.addItem (5, "Mute", true, plugin->isMuted ()); menu.addItem (6, "Bypass", true, plugin->isBypass ()); menu.addItem (7, "Solo", false, false); menu.addSeparator (); synthMidiChanMenu.addItem(2020, "Omni", true, !plugin->getSynthInputChannelFilter() || plugin->getSynthInputChannel() == -1); midiChanMenu.addItem(1020, "Omni", true, !plugin->getMidiOutputChannelFilter() || plugin->getMidiOutputChannel() == -1); for (int i=1; i<17; i++) { synthMidiChanMenu.addItem(2000+i, String("Ch ") + String(i), true, plugin->getSynthInputChannelFilter() && plugin->getSynthInputChannel() == i); midiChanMenu.addItem(1000+i, String("Ch ") + String(i), true, plugin->getMidiOutputChannelFilter() && plugin->getMidiOutputChannel() == i); } menu.addSubMenu (T("Filter synth input MIDI channel"), synthMidiChanMenu); menu.addSubMenu (T("Filter output MIDI channel"), midiChanMenu); menu.addSeparator (); int inputLinks = node->getInputLinksCount (); int outputLinks = node->getOutputLinksCount (); if (inputLinks > 0 && outputLinks > 0) menu.addItem (8, "Disconnect all"); if (inputLinks > 0) menu.addItem (9, "Disconnect inputs"); if (outputLinks > 0) menu.addItem (10, "Disconnect outputs"); menu.addItem (11, String("Rename \"") + plugin->getInstanceName() + String("\"")); menu.addItem (12, "Render stem", true, plugin->getBoolValue(PROP_RENDERSTEM, false)); // only allow changing this if stems aren't rendering right now (i.e. files aren't opened) const int result = menu.show(); switch (result) { case 1: // Open editor { owner->openPluginEditorWindow (plugin); break; } case 2: // set preferred editor plugin->setValue(PROP_WINDOWPREFERGENERIC, !plugin->getBoolValue(PROP_WINDOWPREFERGENERIC, false)); break; case 12: // set stem render option plugin->setValue(PROP_RENDERSTEM, !plugin->getBoolValue(PROP_RENDERSTEM, false)); break; case 3: // Close { if (owner->isPluginEditorWindowOpen (plugin)) owner->closePluginEditorWindow (plugin); if (plugin) { host->closePlugin (plugin); selectedNodes.deselect (node); deletePluginNode (node); graphChanged (); } break; } case 4: // Lock / unlock { bool lockedState = ! node->isLocked (); if (plugin) plugin->setValue (PROP_GRAPHLOCKED, lockedState); node->setLocked (lockedState); node->repaint (); } break; case 5: // Mute { if (plugin) plugin->setMuted (! plugin->isMuted()); } break; case 6: // Bypass { if (plugin) plugin->setBypass (! plugin->isBypass()); } break; case 7: // Solo (TODO) break; case 8: // Disconnect all node->breakAllLinks(); break; case 9: // Disconnect inputs node->breakInputLinks(); break; case 10: // Disconnect outputs node->breakOutputLinks(); break; case 11: // Rename instance { TextEditor instanceName(String("renamePluginInstance")); instanceName.setSize(400, 30); instanceName.setText(plugin->getInstanceName()); DialogWindow::showModalDialog(String("Rename " + plugin->getInstanceName()), &instanceName, node, Colours::yellow, true); String newName = instanceName.getText(); if (newName.isNotEmpty()) setNodeDisplayName(plugin, node, newName); } break; case 1020: plugin->clearMidiOutputFilter(); break; case 2020: plugin->clearSynthInputFilter(); break; default: if (result >= 1001 && result <= 1016) plugin->setMidiOutputChannelFilter(result - 1000); if (result >= 2001 && result <= 2016) plugin->setSynthInputChannelFilter(result - 2000); break; } currentClickedNode = 0; }