void BlockTreeWidget::mouseMoveEvent(QMouseEvent *event) { if(!(event->buttons() & Qt::LeftButton)) { QTreeWidget::mouseMoveEvent(event); return; } if((event->pos() - _dragStartPos).manhattanLength() < QApplication::startDragDistance()) { QTreeWidget::mouseMoveEvent(event); return; } //get the block data auto blockItem = dynamic_cast<BlockTreeWidgetItem *>(itemAt(_dragStartPos)); if (not blockItem->getBlockDesc()) return; //create a block object to render the image auto draw = dynamic_cast<GraphEditorTabs *>(getObjectMap()["editorTabs"])->getCurrentGraphEditor()->getCurrentGraphDraw(); std::shared_ptr<GraphBlock> renderBlock(new GraphBlock(draw)); renderBlock->setBlockDesc(blockItem->getBlockDesc()); renderBlock->prerender(); //precalculate so we can get bounds const auto bounds = renderBlock->boundingRect(); //draw the block's preview onto a mini pixmap QPixmap pixmap(bounds.size().toSize()+QSize(2,2)); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.translate(-bounds.topLeft()+QPoint(1,1)); //painter.scale(zoomScale, zoomScale); //TODO get zoomscale from draw painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::HighQualityAntialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); renderBlock->render(painter); renderBlock.reset(); painter.end(); //create the drag object auto mimeData = new QMimeData(); std::ostringstream oss; blockItem->getBlockDesc()->stringify(oss); QByteArray byteArray(oss.str().c_str(), oss.str().size()); mimeData->setData("text/json/pothos_block", byteArray); auto drag = new QDrag(this); drag->setMimeData(mimeData); drag->setPixmap(pixmap); drag->setHotSpot(-bounds.topLeft().toPoint()); drag->exec(Qt::CopyAction | Qt::MoveAction); }
void BlockTreeWidget::handleSelectionChange(void) { for (auto item : this->selectedItems()) { auto b = dynamic_cast<BlockTreeWidgetItem *>(item); if (b != nullptr) emit blockDescEvent(b->getBlockDesc(), false); } }
QMimeData *BlockTreeWidget::mimeData(const QList<QTreeWidgetItem *> items) const { for (auto item : items) { auto b = dynamic_cast<BlockTreeWidgetItem *>(item); if (b == nullptr) continue; auto mimeData = new QMimeData(); std::ostringstream oss; b->getBlockDesc()->stringify(oss); QByteArray byteArray(oss.str().c_str(), oss.str().size()); mimeData->setData("text/json/pothos_block", byteArray); return mimeData; } return QTreeWidget::mimeData(items); }
void GraphEditor::exportToJSONTopology(const QString &fileName) { poco_information_f1(_logger, "Exporting %s", fileName.toStdString()); Poco::JSON::Object topObj; //all graph objects excluding widgets which are not exported //we will have to filter out graphical blocks as well const auto graphObjects = this->getGraphObjects(~GRAPH_WIDGET); //global variables Poco::JSON::Array globals; for (const auto &name : this->listGlobals()) { const auto &value = this->getGlobalExpression(name); Poco::JSON::Object globalObj; globalObj.set("name", name.toStdString()); globalObj.set("value", value.toStdString()); globals.add(globalObj); } if (globals.size() > 0) topObj.set("globals", globals); //thread pools (filled in by blocks loop) Poco::JSON::Object threadPools; auto affinityZones = AffinityZonesDock::global(); //blocks Poco::JSON::Array blocks; std::map<size_t, const GraphBlock*> uidToBlock; for (const auto *obj : graphObjects) { const auto block = dynamic_cast<const GraphBlock *>(obj); if (block == nullptr) continue; if (block->isGraphWidget()) continue; uidToBlock[block->uid()] = block; //copy in the the id and path Poco::JSON::Object blockObj; blockObj.set("id", block->getId().toStdString()); blockObj.set("path", block->getBlockDescPath()); //setup the thread pool when specified const auto affinityZone = block->getAffinityZone(); if (not affinityZone.isEmpty() and affinityZone != "gui") { const auto config = affinityZones->zoneToConfig(affinityZone); threadPools.set(affinityZone.toStdString(), config); blockObj.set("threadPool", affinityZone.toStdString()); } //block description args are in the same format const auto desc = block->getBlockDesc(); if (desc->has("args")) blockObj.set("args", desc->get("args")); //copy in the named calls in array format Poco::JSON::Array calls; if (desc->isArray("calls")) for (const auto &elem : *desc->getArray("calls")) { const auto callObj = elem.extract<Poco::JSON::Object::Ptr>(); Poco::JSON::Array call; call.add(callObj->get("name")); for (const auto &arg : *callObj->getArray("args")) call.add(arg); calls.add(call); } blockObj.set("calls", calls); //copy in the parameters as local variables Poco::JSON::Array locals; for (const auto &name : block->getProperties()) { Poco::JSON::Object local; local.set("name", name.toStdString()); local.set("value", block->getPropertyValue(name).toStdString()); locals.add(local); } blockObj.set("locals", locals); blocks.add(blockObj); } topObj.set("blocks", blocks); if (threadPools.size() > 0) topObj.set("threadPools", threadPools); //connections Poco::JSON::Array connections; for (const auto &connInfo : TopologyEval::getConnectionInfo(graphObjects)) { //the block may have been filtered out //check that its found in the mapping auto srcIt = uidToBlock.find(connInfo.srcBlockUID); if (srcIt == uidToBlock.end()) continue; auto dstIt = uidToBlock.find(connInfo.dstBlockUID); if (dstIt == uidToBlock.end()) continue; //create the connection information in order Poco::JSON::Array connArr; connArr.add(srcIt->second->getId().toStdString()); connArr.add(connInfo.srcPort); connArr.add(dstIt->second->getId().toStdString()); connArr.add(connInfo.dstPort); connections.add(connArr); } topObj.set("connections", connections); //write to file try { std::ofstream outFile(fileName.toStdString().c_str()); topObj.stringify(outFile, 4/*indent*/); } catch (const std::exception &ex) { poco_error_f2(_logger, "Error exporting %s: %s", fileName, std::string(ex.what())); } }
void BlockTreeWidget::handleItemDoubleClicked(QTreeWidgetItem *item, int) { auto b = dynamic_cast<BlockTreeWidgetItem *>(item); if (b != nullptr) emit blockDescEvent(b->getBlockDesc(), true); }