void GraphDraw::mouseMoveEvent(QMouseEvent *event) { QGraphicsView::mouseMoveEvent(event); //handle the first move event transition from a press event if (_selectionState == SELECTION_STATE_PRESS) { _selectionState = SELECTION_STATE_MOVE; //record positions to determine movement on release _preMovePositions.clear(); for (auto obj : getObjectsSelected(~GRAPH_CONNECTION)) { _preMovePositions[obj] = obj->pos(); } } //cause full render when moving objects for clean animation if (_selectionState == SELECTION_STATE_MOVE) this->render(); //auto scroll near boundaries if (_selectionState != SELECTION_STATE_NONE) { handleAutoScroll(this->horizontalScrollBar(), this->size().width(), this->mapToScene(event->pos()).x()); handleAutoScroll(this->verticalScrollBar(), this->size().height(), this->mapToScene(event->pos()).y()); } }
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 GraphEditor::handleObjectProperties(void) { if (not this->isVisible()) return; auto draw = this->getCurrentGraphDraw(); const auto objs = draw->getObjectsSelected(); if (not objs.isEmpty()) emit draw->modifyProperties(objs.at(0)); }
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::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)))); }
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::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 GraphDraw::mouseMoveEvent(QMouseEvent *event) { QGraphicsView::mouseMoveEvent(event); //implement mouse tracking for blocks const auto scenePos = this->mapToScene(event->pos()); for (auto obj : this->getGraphObjects()) { obj->updateMouseTracking(obj->mapFromParent(scenePos)); } //handle drawing in the click, drag, connect mode const auto topObj = _lastClickSelectEp.getObj(); if (_connectLineItem and topObj) { const auto attrs = topObj->getConnectableAttrs(_lastClickSelectEp.getKey()); const auto newPos = topObj->mapFromParent(scenePos); _connectLineItem->setLine(QLineF(attrs.point, newPos)); } //handle the first move event transition from a press event if (_selectionState == SELECTION_STATE_PRESS) { _selectionState = SELECTION_STATE_MOVE; //record positions to determine movement on release _preMovePositions.clear(); for (auto obj : getObjectsSelected(~GRAPH_CONNECTION)) { _preMovePositions[obj] = obj->pos(); } } //cause full render when moving objects for clean animation if (_selectionState == SELECTION_STATE_MOVE) this->render(); //auto scroll near boundaries if (_selectionState != SELECTION_STATE_NONE) { handleAutoScroll(this->horizontalScrollBar(), this->size().width(), this->mapToScene(event->pos()).x()); handleAutoScroll(this->verticalScrollBar(), this->size().height(), this->mapToScene(event->pos()).y()); } }
void GraphEditor::handleCopy(void) { if (not this->isVisible()) return; auto draw = this->getCurrentGraphDraw(); Poco::JSON::Array jsonObjs; for (auto obj : draw->getObjectsSelected()) { jsonObjs.add(obj->serialize()); } //to byte array std::ostringstream oss; jsonObjs.stringify(oss); QByteArray byteArray(oss.str().data(), oss.str().size()); //load the clipboard auto mimeData = new QMimeData(); mimeData->setData("text/json/pothos_object_array", byteArray); QApplication::clipboard()->setMimeData(mimeData); }
void GraphEditor::handleReeval(void) { if (not this->isVisible()) return; auto draw = this->getCurrentGraphDraw(); _evalEngine->submitReeval(draw->getObjectsSelected(GRAPH_BLOCK)); }
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)); }