void GraphEditor::load(void) { auto fileName = this->getCurrentFilePath().toStdString(); if (fileName.empty()) { _stateManager->resetToDefault(); handleStateChange(GraphState("document-new", tr("Create new topology"))); _stateManager->saveCurrent(); this->render(); return; } try { poco_information_f1(Poco::Logger::get("PothosGui.GraphEditor.load"), "Loading %s from file", fileName); postStatusMessage(tr("Loading %1").arg(QString::fromStdString(fileName))); std::ifstream inFile(fileName.c_str()); this->loadState(inFile); } catch (const std::exception &ex) { poco_error_f2(Poco::Logger::get("PothosGui.GraphEditor.load"), "Error loading %s: %s", fileName, std::string(ex.what())); } _stateManager->resetToDefault(); handleStateChange(GraphState("document-new", tr("Load topology from file"))); _stateManager->saveCurrent(); this->updateGraphEditorMenus(); this->render(); }
void GraphEditor::handleBlockXcrement(const int adj) { if (not this->isVisible()) return; auto draw = this->getCurrentGraphDraw(); GraphObjectList changedObjects; for (auto obj : draw->getObjectsSelected(GRAPH_BLOCK)) { auto block = dynamic_cast<GraphBlock *>(obj); assert(block != nullptr); for (const auto &propKey : block->getProperties()) { auto paramDesc = block->getParamDesc(propKey); if (paramDesc->has("widgetType") and paramDesc->getValue<std::string>("widgetType") == "SpinBox") { const auto newValue = block->getPropertyValue(propKey).toInt() + adj; block->setPropertyValue(propKey, QString("%1").arg(newValue)); changedObjects.push_back(block); break; } } } if (changedObjects.empty()) return; const auto desc = (changedObjects.size() == 1)? changedObjects.front()->getId() : tr("selected"); if (adj > 0) handleStateChange(GraphState("list-add", tr("Increment %1").arg(desc))); if (adj < 0) handleStateChange(GraphState("list-remove", tr("Decrement %1").arg(desc))); }
void Game::run(void) { if (!mInitialized) REQUEST_EXCEPT("No initialization done prior to run() call!", "Game::run"); // no state prepared and no state to be switched to? if (mCurrentState == 0 && ((mTargetState == 0) || !mStateChangeRequested) ) REQUEST_EXCEPT("No state to start the game with!", "Game::run"); // loop while there is something to be done while (!mTerminationRequested) { // if a request to change state happened, do it now if (handleStateChange()) break; unsigned long frameStart = mOgreRoot.getTimer()->getMicroseconds(); unsigned long deltaTime = frameStart - mLastFrameTime; mLastFrameTime = frameStart; float deltaSec = deltaTime / 1000000.0f; // TODO: Accumulate the deltaSec if it is too small // handle the frame... mInputSys->update(deltaSec); mCurrentState->update(deltaSec); mEffectSys->update(deltaSec); mRendererSys->update(deltaSec); } }
void GraphEditor::handleSetEnabled(const bool enb) { if (not this->isVisible()) return; auto draw = this->getCurrentGraphDraw(); auto objs = draw->getObjectsSelected(); if (objs.isEmpty()) return; for (auto obj : objs) { obj->setEnabled(enb); } if (enb) handleStateChange(GraphState("document-import", tr("Enable %1").arg(draw->getSelectionDescription()))); else handleStateChange(GraphState("document-export", tr("Disable %1").arg(draw->getSelectionDescription()))); }
void GraphEditor::handleAddBlock(const Poco::JSON::Object::Ptr &blockDesc, const QPointF &where) { if (not blockDesc) return; auto draw = this->getCurrentGraphDraw(); auto block = new GraphBlock(draw); block->setBlockDesc(blockDesc); QString hint; const auto title = block->getTitle(); for (int i = 0; i < title.length(); i++) { if (i == 0 and title.at(i).isNumber()) hint.append(QChar('_')); if (title.at(i).isLetterOrNumber() or title.at(i).toLatin1() == '_') { hint.append(title.at(i)); } } block->setId(this->newId(hint)); //set highest z-index on new block block->setZValue(draw->getMaxZValue()+1); block->setPos(where); block->setRotation(0); handleStateChange(GraphState("list-add", tr("Create block %1").arg(title))); }
//Uses and modify's the state of the interp according to the commands given void translateBF(BFState * interp, char * commands){ int iP = 0; //Instruction pointer for(;iP > -1 && iP < (int)strlen(commands); iP++){ if( commands[iP] == '[' ){ //if the byte at the data pointer is zero, then instead of moving //the instruction pointer forward to the next command, jump it forward to the command after the matching ] command. if(interp->tape[interp->dataPointer] == 0){ //Find the matching ], if we don't find it before we run out of commands print an error and run away iP = findRightBrace(commands,iP); if(iP < 0){ //No matching brace run away: puts("No Matching Brace for handled [. Please check your program") ; //Subtract because iP++ will push us back from -1 to 0 and the instruction loop will continue. iP--; } //We'll automatically be pointing at the command after the ] when we loop around the for } }else if( commands[iP]==']'){ //if the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward //to the next command, jump it back to the command after the matching [ command. if(interp->tape[interp->dataPointer] != 0){ iP = findLeftBrace(commands,iP); if(iP < 0){ puts("No Matching Brace for handled ]. Please check your program"); //Subtract because iP++ will push us back from -1 to 0 and the instruction loop will continue. iP--; } } }else{ handleStateChange(interp,commands[iP]); } } }
void Airplay :: start() { // read the airplay pipe file.setFileName("/tmp/shairport-sync-pipe"); file.open(QIODevice::ReadOnly); // set the audio format // https://github.com/mikebrady/shairport-sync/issues/126 // Playing raw data 'stdin' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo QAudioFormat format; format.setSampleRate(44100); // rate format.setChannelCount(2); // stereo format.setCodec("audio/pcm"); // raw format.setSampleSize(16); // 16 bit format.setByteOrder(QAudioFormat::LittleEndian); format.setSampleType(QAudioFormat::SignedInt); // check format is supported if (!deviceInfo.isFormatSupported(format)) qWarning() << "Output format not supported"; // connect signals audio = new QAudioOutput(deviceInfo, format, this); connect(audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChange(QAudio::State))); // start playing audio->start(&file); }
void GraphEditor::handleDeleteGraphPage(void) { if (not this->isVisible()) return; const auto oldName = this->tabText(this->currentIndex()); this->removeTab(this->currentIndex()); if (this->count() == 0) this->makeDefaultPage(); this->updateGraphEditorMenus(); handleStateChange(GraphState("edit-delete", tr("Delete graph page ") + oldName)); }
void GraphEditor::handleCreateGraphPage(void) { if (not this->isVisible()) return; const QString newName = QInputDialog::getText(this, tr("Create page"), tr("New page name"), QLineEdit::Normal, tr("untitled")); if (newName.isEmpty()) return; this->addTab(new GraphDraw(this), newName); this->updateGraphEditorMenus(); handleStateChange(GraphState("document-new", tr("Create graph page ") + newName)); }
void GraphEditor::handleRotateRight(void) { if (not this->isVisible()) return; auto draw = this->getCurrentGraphDraw(); //TODO rotate group of objects around central point for (auto obj : draw->getObjectsSelected(~GRAPH_CONNECTION)) { obj->rotateRight(); } handleStateChange(GraphState("object-rotate-right", tr("Rotate %1 right").arg(draw->getSelectionDescription(~GRAPH_CONNECTION)))); }
void GraphEditor::handleRenameGraphPage(void) { if (not this->isVisible()) return; const auto oldName = this->tabText(this->currentIndex()); const QString newName = QInputDialog::getText(this, tr("Rename page"), tr("New page name"), QLineEdit::Normal, oldName); if (newName.isEmpty()) return; this->setTabText(this->currentIndex(), newName); this->updateGraphEditorMenus(); handleStateChange(GraphState("edit-rename", tr("Rename graph page ") + oldName + " -> " + newName)); }
void GraphEditor::handleAffinityZoneClicked(const QString &zone) { if (not this->isVisible()) return; auto draw = this->getCurrentGraphDraw(); for (auto obj : draw->getObjectsSelected(GRAPH_BLOCK)) { auto block = dynamic_cast<GraphBlock *>(obj); assert(block != nullptr); block->setAffinityZone(zone); } handleStateChange(GraphState("document-export", tr("Set %1 affinity zone").arg(draw->getSelectionDescription(GRAPH_BLOCK)))); }
/****************************************************************************** * CodecCommander::onTimerAction - repeats the action each time timer fires ******************************************************************************/ void CodecCommander::onTimerAction() { // check if hda codec is powered - we are monitoring ocurrences of fugue state parseCodecPowerState(); // if no power after semi-sleep (fugue) state and power was restored - set EAPD bit if (eapdPoweredDown && hdaCurrentPowerState != 0x0) { DEBUG_LOG("CodecCommander: cc: --> hda codec power restored\n"); handleStateChange(kStateWake); } mTimer->setTimeoutMS(mConfiguration->getInterval()); }
/****************************************************************************** * CodecCommander::setPowerState - set active power state ******************************************************************************/ IOReturn CodecCommander::setPowerState(unsigned long powerStateOrdinal, IOService *policyMaker) { if (kPowerStateSleep == powerStateOrdinal) { DEBUG_LOG("CodecCommander: cc: --> asleep\n"); handleStateChange(kStateSleep); // set EAPD logic level 0 to cause EAPD to power off properly eapdPoweredDown = true; // now it's powered down for sure coldBoot = false; } else if (kPowerStateNormal == powerStateOrdinal) { DEBUG_LOG("CodecCommander: cc: --> awake\n"); // issue codec reset at wake and cold boot performCodecReset(); if (eapdPoweredDown) // set EAPD bit at wake or cold boot handleStateChange(kStateWake); // if infinite checking requested if (mConfiguration->getCheckInfinite()) { // if checking infinitely then make sure to delay workloop if (coldBoot) mTimer->setTimeoutMS(20000); // create a nasty 20sec delay for AudioEngineOutput to initialize // if we are waking it will be already initialized else mTimer->setTimeoutMS(100); // so fire timer for workLoop almost immediately DEBUG_LOG("CodecCommander: cc: --> workloop started\n"); } } return IOPMAckImplied; }
void GraphEditor::handleDelete(void) { if (not this->isVisible()) return; auto draw = this->getCurrentGraphDraw(); auto desc = tr("Delete %1").arg(draw->getSelectionDescription()); //delete all selected graph objects for (auto obj : draw->getObjectsSelected()) { delete obj; } this->deleteFlagged(); handleStateChange(GraphState("edit-delete", desc)); }
void GraphEditor::handleInsertGraphWidget(QObject *obj) { auto block = dynamic_cast<GraphBlock *>(obj); assert(block != nullptr); assert(block->isGraphWidget()); auto draw = this->getCurrentGraphDraw(); auto display = new GraphWidget(draw); display->setGraphBlock(block); display->setId(this->newId("Widget"+block->getId())); display->setZValue(draw->getMaxZValue()+1); display->setPos(draw->getLastContextMenuPos()); display->setRotation(0); handleStateChange(GraphState("insert-image", tr("Insert widget %1").arg(block->getId()))); }
void GraphEditor::handleCreateBreaker(const bool isInput) { if (not this->isVisible()) return; const auto dirName = isInput?tr("input"):tr("output"); const auto newName = QInputDialog::getText(this, tr("Create %1 breaker").arg(dirName), tr("New breaker node name"), QLineEdit::Normal, tr("untitled")); if (newName.isEmpty()) return; auto draw = this->getCurrentGraphDraw(); auto breaker = new GraphBreaker(draw); breaker->setInput(isInput); breaker->setNodeName(newName); breaker->setId(this->newId(newName)); breaker->setPos(draw->getLastContextMenuPos()); handleStateChange(GraphState("document-new", tr("Create %1 breaker %2").arg(dirName, newName))); }
void ProcessDialog::runUic() { ui.uicButton->setEnabled( false ); ui.textEdit->setText( "" ); if( process ) delete process; process = new QProcess( this ); connect( process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(handleError(QProcess::ProcessError)) ); connect( process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(handleFinish(int,QProcess::ExitStatus)) ); connect( process, SIGNAL(readyReadStandardError()), this, SLOT(handleReadStandardError()) ); connect( process, SIGNAL(readyReadStandardOutput()), this, SLOT(handleReadStandardOutput()) ); connect( process, SIGNAL(started()), this, SLOT(handleStarted()) ); connect( process, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(handleStateChange(QProcess::ProcessState)) ); QStringList arguments; arguments << "-tr" << "MYTR" << "processdialog.ui"; process->start( "uic", arguments ); }
int Player::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QWidget::qt_metacall(_c, _id, _a); if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod) { switch (_id) { case 0: hideWindow(); break; case 1: open(); break; case 2: durationChanged((*reinterpret_cast< qint64(*)>(_a[1]))); break; case 3: positionChanged((*reinterpret_cast< qint64(*)>(_a[1]))); break; case 4: metaDataChanged(); break; case 5: previousClicked(); break; case 6: seek((*reinterpret_cast< int(*)>(_a[1]))); break; case 7: jump((*reinterpret_cast< const QModelIndex(*)>(_a[1]))); break; case 8: playlistPositionChanged((*reinterpret_cast< int(*)>(_a[1]))); break; case 9: statusChanged((*reinterpret_cast< QMediaPlayer::MediaStatus(*)>(_a[1]))); break; case 10: bufferingProgress((*reinterpret_cast< int(*)>(_a[1]))); break; case 11: displayErrorMessage(); break; case 12: handleAspectRatio((*reinterpret_cast< bool(*)>(_a[1]))); break; case 13: handleStateChange((*reinterpret_cast< QMediaPlayer::State(*)>(_a[1]))); break; case 14: showPlayList(); break; case 15: hideOrShowCoverArt(); break; case 16: launchYoutubeDialog(); break; case 17: youtubeHttpRequestFinished((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< bool(*)>(_a[2]))); break; case 18: youtubeReadResponseHeader((*reinterpret_cast< const QHttpResponseHeader(*)>(_a[1]))); break; case 19: searchYoutubeVideo(); break; case 20: addYoutubeVideo(); break; case 21: handleAudioOutputDefault(); break; case 22: handleAudioOutputAll(); break; case 23: handleAudioOutputNone(); break; case 24: handleAudioOutputEarphone(); break; case 25: handleAudioOutputSpeaker(); break; case 26: handleAudioOutputChangedSignal((*reinterpret_cast< const QString(*)>(_a[1]))); break; default: ; } _id -= 27; } return _id; }
/****************************************************************************** * CodecCommander::parseCodecPowerState - get codec power state from IOReg ******************************************************************************/ void CodecCommander::parseCodecPowerState() { // monitor power state of hda audio codec IORegistryEntry *hdaDriverEntry = IORegistryEntry::fromPath(mConfiguration->getHDADriverPath()); if (hdaDriverEntry != NULL) { OSNumber *powerState = OSDynamicCast(OSNumber, hdaDriverEntry->getProperty("IOAudioPowerState")); if (powerState != NULL) { hdaCurrentPowerState = powerState->unsigned8BitValue(); // if hda codec changed power state if (hdaCurrentPowerState != hdaPrevPowerState) { DEBUG_LOG("CodecCommander: cc - power state transition from %d to %d recorded\n", hdaPrevPowerState, hdaCurrentPowerState); // store current power state as previous state for next workloop cycle hdaPrevPowerState = hdaCurrentPowerState; // notify about codec power loss state if (hdaCurrentPowerState == 0x0) { DEBUG_LOG("CodecCommander: HDA codec lost power\n"); handleStateChange(kStateSleep); // power down EAPDs properly eapdPoweredDown = true; coldBoot = false; //codec entered fugue state or sleep - no longer a cold boot } } } else DEBUG_LOG("CodecCommander: IOAudioPowerState unknown\n"); hdaDriverEntry->release(); } else DEBUG_LOG("CodecCommander: %s is unreachable\n", mConfiguration->getHDADriverPath()); }
void Airplay :: stop() { handleStateChange(QAudio::IdleState); }
void GraphEditor::handleMoveGraphObjects(const int index) { if (not this->isVisible()) return; if (index >= this->count()) return; auto draw = this->getCurrentGraphDraw(); auto desc = tr("Move %1 to %2").arg(draw->getSelectionDescription(~GRAPH_CONNECTION), this->tabText(index)); //move all selected objects for (auto obj : draw->getObjectsSelected()) { obj->setSelected(false); this->getGraphDraw(index)->scene()->addItem(obj); } //reparent all connections based on endpoints: std::vector<GraphConnection *> boundaryConnections; for (auto obj : this->getGraphObjects(GRAPH_CONNECTION)) { auto conn = dynamic_cast<GraphConnection *>(obj); assert(conn != nullptr); //Connection has the same endpoints, so make sure that the parent is corrected to the endpoint if (conn->getOutputEndpoint().getObj()->scene() == conn->getInputEndpoint().getObj()->scene()) { if (conn->getOutputEndpoint().getObj()->scene() != conn->scene()) { conn->getInputEndpoint().getObj()->scene()->addItem(conn); } } //otherwise stash it for more processing else { boundaryConnections.push_back(conn); } } //create breakers for output endpoints that have to cross for (auto conn : boundaryConnections) { const auto &epOut = conn->getOutputEndpoint(); const auto &epIn = conn->getInputEndpoint(); auto sigSlotPairs = conn->getSigSlotPairs(); if (sigSlotPairs.empty()) sigSlotPairs.resize(1); //add empty for (const auto &sigSlotPair : sigSlotPairs) { auto breaker = findInputBreaker(this, epOut); if (breaker != nullptr) continue; breaker = new GraphBreaker(epOut.getObj()->draw()); breaker->setInput(true); const auto name = QString("%1[%2]").arg(epOut.getObj()->getId(), epOut.getKey().id); breaker->setId(this->newId(name)); breaker->setNodeName(breaker->getId()); //the first of its name breaker->setRotation(epIn.getObj()->rotation()); breaker->setPos(epIn.getObj()->pos()); auto outConn = this->makeConnection(epOut, GraphConnectionEndpoint(breaker, breaker->getConnectableKeys().at(0))); if (not sigSlotPair.first.isEmpty()) outConn->addSigSlotPair(std::make_pair(sigSlotPair.first, breaker->getConnectableKeys().at(0).id)); if (outConn->scene() != breaker->scene()) breaker->scene()->addItem(outConn); //use desired parent } } //create breakers for input endpoints that have to cross for (auto conn : boundaryConnections) { const auto &epOut = conn->getOutputEndpoint(); const auto &epIn = conn->getInputEndpoint(); auto sigSlotPairs = conn->getSigSlotPairs(); if (sigSlotPairs.empty()) sigSlotPairs.resize(1); //add empty for (const auto &sigSlotPair : sigSlotPairs) { //find the existing breaker or make a new one const auto name = findInputBreaker(this, epOut)->getNodeName(); GraphBreaker *breaker = nullptr; for (auto obj : this->getGraphObjects(GRAPH_BREAKER)) { if (obj->draw() != epIn.getObj()->draw()) continue; auto outBreaker = dynamic_cast<GraphBreaker *>(obj); assert(outBreaker != nullptr); if (outBreaker->isInput()) continue; if (outBreaker->getNodeName() != name) continue; breaker = outBreaker; break; } //make a new output breaker if (breaker == nullptr) { breaker = new GraphBreaker(epIn.getObj()->draw()); breaker->setInput(false); breaker->setId(this->newId(name)); breaker->setNodeName(name); breaker->setRotation(epOut.getObj()->rotation()); breaker->setPos(epOut.getObj()->pos()); } //connect to this breaker auto inConn = this->makeConnection(epIn, GraphConnectionEndpoint(breaker, breaker->getConnectableKeys().at(0))); if (not sigSlotPair.second.isEmpty()) inConn->addSigSlotPair(std::make_pair(breaker->getConnectableKeys().at(0).id, sigSlotPair.second)); if (inConn->scene() != breaker->scene()) breaker->scene()->addItem(inConn); //use desired parent } delete conn; } handleStateChange(GraphState("transform-move", desc)); }
/****************************************************************************** * CodecCommander::start - start kernel extension and init PM ******************************************************************************/ bool CodecCommander::start(IOService *provider) { IOLog("CodecCommander: Version 2.2.1 starting.\n"); if (!provider || !super::start(provider)) { DEBUG_LOG("CodecCommander: Error loading kernel extension.\n"); return false; } // Retrieve HDEF device from IORegistry IORegistryEntry *hdaDeviceEntry = IORegistryEntry::fromPath(mConfiguration->getHDADevicePath()); if (hdaDeviceEntry != NULL) { mIntelHDA = new IntelHDA(hdaDeviceEntry, PIO, mConfiguration->getCodecNumber()); OSSafeRelease(hdaDeviceEntry); } else { DEBUG_LOG("CodecCommander: Device \"%s\" is unreachable, start aborted.\n", mConfiguration->getHDADevicePath()); return false; } if (mConfiguration->getUpdateNodes()) { IOSleep(mConfiguration->getSendDelay()); // need to wait a bit until codec can actually respond to immediate verbs int k = 0; // array index // Fetch Pin Capabilities from the range of nodes DEBUG_LOG("CodecCommander: Getting EAPD supported node list (limited to %d)\n", MAX_EAPD_NODES); for (int nodeId = mIntelHDA->getStartingNode(); nodeId <= mIntelHDA->getTotalNodes(); nodeId++) { UInt32 response = mIntelHDA->sendCommand(nodeId, HDA_VERB_GET_PARAM, HDA_PARM_PINCAP); if (response == -1) { DEBUG_LOG("CodecCommander: Failed to retrieve pin capabilities for node 0x%02x.\n", nodeId); continue; } // if bit 16 is set in pincap - node supports EAPD if (HDA_PINCAP_IS_EAPD_CAPABLE(response)) { eapdCapableNodes[k] = nodeId; k++; IOLog("CodecCommander: NID=0x%02x supports EAPD, will update state after sleep\n", nodeId); } } /* IOLog("CodecCommander:: Set 0x0A result: 0x%08x\n", mIntelHDA->sendCommand(0x0A, HDA_VERB_SET_AMP_GAIN, HDA_PARM_AMP_GAIN_SET(0x80, 0, 1, 1, 1, 0, 1))); IOLog("CodecCommander:: Set 0x0B result: 0x%08x\n", mIntelHDA->sendCommand(0x0B, HDA_VERB_SET_AMP_GAIN, HDA_PARM_AMP_GAIN_SET(0x80, 0, 1, 1, 1, 0, 1))); IOLog("CodecCommander:: Set 0x0C result: 0x%08x\n", mIntelHDA->sendCommand(0x0C, HDA_VERB_SET_AMP_GAIN, HDA_PARM_AMP_GAIN_SET(0x80, 0, 1, 1, 1, 0, 1))); for (int nodeId = mIntelHDA->getStartingNode(); nodeId <= mIntelHDA->getTotalNodes(); nodeId++) { UInt16 payload = HDA_PARM_AMP_GAIN_GET(0, 1, 1);//AC_AMP_GET_OUTPUT | AC_AMP_GET_LEFT; UInt32 response = mIntelHDA->sendCommand(nodeId, HDA_VERB_GET_AMP_GAIN, payload); if (response == -1) { DEBUG_LOG("Failed to retrieve amp gain settings for node 0x%02x.\n", nodeId); continue; } IOLog("CodecCommander:: [Amp Gain] Node: 0x%04x, Response: 0x%08x\n", nodeId, response); } */ } // Execute any custom commands registered for initialization handleStateChange(kStateInit); // notify about extra feature requests if (mConfiguration->getCheckInfinite()) DEBUG_LOG("CodecCommander: Infinite workloop requested, will start now!\n"); // init power state management & set state as PowerOn PMinit(); registerPowerDriver(this, powerStateArray, kPowerStateCount); provider->joinPMtree(this); // setup workloop and timer mWorkLoop = IOWorkLoop::workLoop(); mTimer = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &CodecCommander::onTimerAction)); if (!mWorkLoop || !mTimer) stop(provider);; if (mWorkLoop->addEventSource(mTimer) != kIOReturnSuccess) stop(provider); this->registerService(0); return true; }
void GraphEditor::handlePaste(void) { if (not this->isVisible()) return; auto draw = this->getCurrentGraphDraw(); auto mimeData = QApplication::clipboard()->mimeData(); const bool canPaste = mimeData->hasFormat("text/json/pothos_object_array") and not mimeData->data("text/json/pothos_object_array").isEmpty(); if (not canPaste) return; //extract object array const auto data = mimeData->data("text/json/pothos_object_array"); const std::string dataStr(data.constData(), data.size()); std::istringstream iss(dataStr); Poco::JSON::Parser p; p.parse(iss); auto graphObjects = p.getHandler()->asVar().extract<Poco::JSON::Array::Ptr>(); assert(graphObjects); //rewrite ids std::map<std::string, std::string> oldIdToNew; for (size_t objIndex = 0; objIndex < graphObjects->size(); objIndex++) { const auto jGraphObj = graphObjects->getObject(objIndex); auto oldId = jGraphObj->getValue<std::string>("id"); oldIdToNew[oldId] = this->newId(QString::fromStdString(oldId)).toStdString(); } for (size_t objIndex = 0; objIndex < graphObjects->size();) { for (auto &pair : *graphObjects->getObject(objIndex)) { if (QString::fromStdString(pair.first).endsWith("id", Qt::CaseInsensitive)) { //if not in oldIdToNew, remove from list if (oldIdToNew.count(pair.second) == 0) { graphObjects->remove(objIndex); goto nextObj; } pair.second = oldIdToNew[pair.second]; } } objIndex++; nextObj: continue; } //unselect all objects draw->deselectAllObjs(); //create objects GraphObjectList objsToMove; objsToMove.append(handlePasteType(draw, graphObjects, "Block")); objsToMove.append(handlePasteType(draw, graphObjects, "Breaker")); handlePasteType(draw, graphObjects, "Connection"); //dont append, connection position doesnt matter objsToMove.append(handlePasteType(draw, graphObjects, "Widget")); //deal with initial positions of pasted objects QPointF cornerest(1e6, 1e6); for (auto obj : objsToMove) { cornerest.setX(std::min(cornerest.x(), obj->pos().x())); cornerest.setY(std::min(cornerest.y(), obj->pos().y())); } //determine an acceptable position to center the paste auto view = dynamic_cast<QGraphicsView *>(this->currentWidget()); auto pastePos = view->mapToScene(view->mapFromGlobal(QCursor::pos())); if (not view->sceneRect().contains(pastePos)) { pastePos = view->mapToScene(this->size().width()/2, this->size().height()/2); } //move objects into position for (auto obj : objsToMove) obj->setPos(obj->pos()-cornerest+pastePos); handleStateChange(GraphState("edit-paste", tr("Paste %1").arg(draw->getSelectionDescription()))); }