Exemple #1
0
static GraphBreaker *findInputBreaker(GraphEditor *editor, const GraphConnectionEndpoint &ep)
{
    for (auto obj : editor->getGraphObjects(GRAPH_CONNECTION))
    {
        auto conn = dynamic_cast<GraphConnection *>(obj);
        assert(conn != nullptr);
        if (not (conn->getOutputEndpoint().getObj()->scene() == conn->getInputEndpoint().getObj()->scene())) continue;
        if (not (conn->getOutputEndpoint() == ep)) continue;
        auto breaker = dynamic_cast<GraphBreaker *>(conn->getInputEndpoint().getObj().data());
        if (breaker == nullptr) continue;
        return breaker;
    }
    return nullptr;
}
QString GraphDraw::getSelectionDescription(const int selectionFlags)
{
    //generate names based on the selected objects
    const auto selected = this->getObjectsSelected(selectionFlags);
    if (selected.isEmpty()) return tr("no selection");

    //if a single connection is selected, pretty print its endpoint IDs
    if (selected.size() == 1)
    {
        auto conn = qobject_cast<GraphConnection *>(selected.at(0));
        if (conn == nullptr) return selected.at(0)->getId();
        return tr("%1[%2] to %3[%4]").arg(
            conn->getOutputEndpoint().getObj()->getId(),
            conn->getOutputEndpoint().getKey().id,
            conn->getInputEndpoint().getObj()->getId(),
            conn->getInputEndpoint().getKey().id
        );
    }
    return tr("selected");
}
Exemple #3
0
GraphConnection *GraphEditor::makeConnection(const GraphConnectionEndpoint &ep0, const GraphConnectionEndpoint &ep1)
{
    //direction check
    if (ep0.getConnectableAttrs().direction == ep1.getConnectableAttrs().direction or
        (ep0.getConnectableAttrs().direction == GRAPH_CONN_INPUT and ep1.getConnectableAttrs().direction == GRAPH_CONN_SLOT) or
        (ep0.getConnectableAttrs().direction == GRAPH_CONN_OUTPUT and ep1.getConnectableAttrs().direction == GRAPH_CONN_SIGNAL) or
        (ep0.getConnectableAttrs().direction == GRAPH_CONN_SLOT and ep1.getConnectableAttrs().direction == GRAPH_CONN_INPUT) or
        (ep0.getConnectableAttrs().direction == GRAPH_CONN_SIGNAL and ep1.getConnectableAttrs().direction == GRAPH_CONN_OUTPUT))
    {
        throw Pothos::Exception("GraphEditor::makeConnection()", "cant connect endpoints of the same direction");
    }

    //duplicate check
    for (auto obj : this->getGraphObjects(GRAPH_CONNECTION))
    {
        auto conn = dynamic_cast<GraphConnection *>(obj);
        assert(conn != nullptr);
        if (
            (conn->getOutputEndpoint() == ep0 and conn->getInputEndpoint() == ep1) or
            (conn->getOutputEndpoint() == ep1 and conn->getInputEndpoint() == ep0)
        ) throw Pothos::Exception("GraphEditor::makeConnection()", "connection already exists");
    }

    auto conn = new GraphConnection(ep0.getObj()->draw());
    conn->setupEndpoint(ep0);
    conn->setupEndpoint(ep1);

    const auto idHint = QString("Connection_%1%2_%3%4").arg(
        conn->getOutputEndpoint().getObj()->getId(),
        conn->getOutputEndpoint().getKey().id,
        conn->getInputEndpoint().getObj()->getId(),
        conn->getInputEndpoint().getKey().id
    );
    conn->setId(this->newId(idHint));
    assert(conn->getInputEndpoint().isValid());
    assert(conn->getOutputEndpoint().isValid());

    return conn;
}
Exemple #4
0
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));
}