Esempio n. 1
0
void
NodeGraph::mouseMoveEvent(QMouseEvent* e)
{
    QPointF newPos = mapToScene( e->pos() );
    QPointF lastMousePosScene = mapToScene( _imp->_lastMousePos.x(), _imp->_lastMousePos.y() );
    double dx, dy;
    {
        QPointF newPosRoot = _imp->_root->mapFromScene(newPos);
        QPointF lastMousePosRoot = _imp->_root->mapFromScene(lastMousePosScene);
        dx = newPosRoot.x() - lastMousePosRoot.x();
        dy = newPosRoot.y() - lastMousePosRoot.y();
    }

    _imp->_hasMovedOnce = true;

    bool mustUpdate = true;
    boost::shared_ptr<NodeCollection> collection = getGroup();
    NodeGroup* isGroup = dynamic_cast<NodeGroup*>( collection.get() );
    bool isGroupEditable = true;
    bool groupEdited = true;
    if (isGroup) {
        isGroupEditable = isGroup->isSubGraphEditable();
        groupEdited = isGroup->getNode()->hasPyPlugBeenEdited();
    }
    if (!groupEdited && isGroupEditable) {
        ///check if user is nearby unlock
        int iw = _imp->unlockIcon.width();
        int ih = _imp->unlockIcon.height();
        int w = width();
        if ( ( e->x() >= (w - iw - 10 - 15) ) && ( e->x() <= (w - 10 + 15) ) &&
                ( e->y() >= (10 - 15) ) && ( e->y() <= (10 + ih + 15) ) ) {
            assert(isGroup);
            QPoint pos = mapToGlobal( e->pos() );
            QToolTip::showText( pos, GuiUtils::convertFromPlainText(QCoreApplication::translate("NodeGraph", "Clicking the unlock button will convert the PyPlug to a regular group saved in the project and dettach it from the script.\n"
                                "Any modification will not be written to the Python script. Subsequent loading of the project will no longer load this group from the python script."), Qt::WhiteSpaceNormal) );
        }
    }

    QRectF sceneR = visibleSceneRect();
    if ( groupEdited && (_imp->_evtState != eEventStateSelectionRect) && (_imp->_evtState != eEventStateDraggingArrow) ) {
        // Set cursor

        std::set<NodeGui*> visibleNodes;
        getNodesWithinViewportRect(visibleWidgetRect(), &visibleNodes);

        NodeGuiPtr selected;
        Edge* selectedEdge = 0;
        bool optionalInputsAutoHidden = areOptionalInputsAutoHidden();

        for (std::set<NodeGui*>::iterator it = visibleNodes.begin(); it != visibleNodes.end(); ++it) {
            QPointF evpt = (*it)->mapFromScene(newPos);
            QRectF bbox = (*it)->mapToScene( (*it)->boundingRect() ).boundingRect();
            if ( (*it)->isActive() && bbox.intersects(sceneR) ) {
                if ( (*it)->contains(evpt) ) {
                    selected = (*it)->shared_from_this();
                    if (optionalInputsAutoHidden) {
                        (*it)->refreshEdgesVisility(true);
                    } else {
                        break;
                    }
                } else {
                    Edge* edge = (*it)->hasEdgeNearbyPoint(newPos);
                    if (edge) {
                        selectedEdge = edge;
                        if (!optionalInputsAutoHidden) {
                            break;
                        }
                    } else if ( optionalInputsAutoHidden && !(*it)->getIsSelected() ) {
                        (*it)->refreshEdgesVisility(false);
                    }
                }
            }
        }
        if (selected) {
            _imp->cursorSet = true;
            setCursor( QCursor(Qt::OpenHandCursor) );
        } else if (selectedEdge) {
        } else if (!selectedEdge && !selected) {
            if (_imp->cursorSet) {
                _imp->cursorSet = false;
                unsetCursor();
            }
        }
    }

    bool mustUpdateNavigator = false;
    ///Apply actions
    switch (_imp->_evtState) {
    case eEventStateDraggingArrow: {
        QPointF np = _imp->_arrowSelected->mapFromScene(newPos);
        if ( _imp->_arrowSelected->isOutputEdge() ) {
            _imp->_arrowSelected->dragDest(np);
        } else {
            _imp->_arrowSelected->dragSource(np);
        }
        checkAndStartAutoScrollTimer(newPos);
        mustUpdate = true;
        break;
    }
    case eEventStateDraggingNode: {
        mustUpdate = true;
        mustUpdateNavigator = true;
        bool controlDown = modifierHasControl(e);
        bool shiftdown = modifierHasShift(e);
        moveSelectedNodesBy(shiftdown, controlDown, lastMousePosScene, newPos, sceneR, true);
        break;
    }
    case eEventStateMovingArea: {
        mustUpdateNavigator = true;
        moveRootInternal(dx, dy);
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::SizeAllCursor) );
        mustUpdate = true;
        break;
    }
    case eEventStateResizingBackdrop: {
        mustUpdateNavigator = true;
        assert(_imp->_backdropResized);
        QPointF p = _imp->_backdropResized->scenePos();
        int w = newPos.x() - p.x();
        int h = newPos.y() - p.y();
        checkAndStartAutoScrollTimer(newPos);
        mustUpdate = true;
        pushUndoCommand( new ResizeBackdropCommand(_imp->_backdropResized, w, h) );
        break;
    }
    case eEventStateSelectionRect: {
        QPointF startDrag = _imp->_lastSelectionStartPointScene;
        QPointF cur = newPos;
        double xmin = std::min( cur.x(), startDrag.x() );
        double xmax = std::max( cur.x(), startDrag.x() );
        double ymin = std::min( cur.y(), startDrag.y() );
        double ymax = std::max( cur.y(), startDrag.y() );
        checkAndStartAutoScrollTimer(newPos);
        QRectF selRect(xmin, ymin, xmax - xmin, ymax - ymin);
        _imp->_selectionRect = selRect;
        mustUpdate = true;
        break;
    }
    case eEventStateDraggingNavigator: {
        QPointF mousePosSceneCoordinates;
        bool insideNavigator = isNearbyNavigator(e->pos(), mousePosSceneCoordinates);
        if (insideNavigator) {
            _imp->_refreshOverlays = true;
            centerOn(mousePosSceneCoordinates);
            _imp->_lastMousePos = e->pos();
            update();

            return;
        }
        break;
    }
    case eEventStateZoomingArea: {
        int delta = 2 * ( ( e->x() - _imp->_lastMousePos.x() ) - ( e->y() - _imp->_lastMousePos.y() ) );
        setTransformationAnchor(QGraphicsView::AnchorViewCenter);
        wheelEventInternal(modCASIsControl(e), delta);
        setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
        mustUpdate = true;
        break;
    }
    default:
        mustUpdate = false;
        break;
    } // switch


    _imp->_lastMousePos = e->pos();


    if (mustUpdateNavigator) {
        _imp->_refreshOverlays = true;
        mustUpdate = true;
    }

    if (mustUpdate) {
        update();
    }
    QGraphicsView::mouseMoveEvent(e);
} // mouseMoveEvent
Esempio n. 2
0
void
NodeGraph::mouseMoveEvent(QMouseEvent* e)
{
    QPointF newPos = mapToScene( e->pos() );
    QPointF lastMousePosScene = mapToScene( _imp->_lastMousePos.x(), _imp->_lastMousePos.y() );
    double dx, dy;
    {
        QPointF newPosRoot = _imp->_root->mapFromScene(newPos);
        QPointF lastMousePosRoot = _imp->_root->mapFromScene(lastMousePosScene);
        dx = newPosRoot.x() - lastMousePosRoot.x();
        dy = newPosRoot.y() - lastMousePosRoot.y();
    }

    _imp->_hasMovedOnce = true;

    bool mustUpdate = true;
    NodeCollectionPtr collection = getGroup();
    NodeGroupPtr isGroup = toNodeGroup(collection);
    bool isGroupEditable = true;
    bool groupEdited = true;
    if (isGroup) {
        isGroupEditable = isGroup->isSubGraphEditable();
        groupEdited = isGroup->isSubGraphEditedByUser();
    }
    if (!groupEdited && isGroupEditable) {
        ///check if user is nearby unlock
        // see NodeGraph::paintEvent()
        QPoint pixPos = _imp->getPyPlugUnlockPos();
        int pixW = _imp->unlockIcon.width();
        int pixH = _imp->unlockIcon.height();
        QRect pixRect(pixPos.x(), pixPos.y(), pixW, pixH);
        pixRect.adjust(-2, -2, 2, 2);
        QRect selRect = pixRect;
        selRect.adjust(-3, -3, 3, 3);
        if ( selRect.contains( e->pos() ) ) {
            assert(isGroup);
            QPoint pos = mapToGlobal( e->pos() );
            // Unfortunately, the timeout delay for the tooltip is hardcoded in Qt 4, and the last parameter to showText doesn't seem to influence anything
            // Can not fix https://github.com/MrKepzie/Natron/issues/1151 (at least in Qt4)
            QToolTip::showText( pos, NATRON_NAMESPACE::convertFromPlainText(QCoreApplication::translate("NodeGraph", "Clicking the unlock button will convert the PyPlug to a regular group saved in the project and dettach it from the script.\n"
                                                                                                "Any modification will not be written to the Python script. Subsequent loading of the project will no longer load this group from the python script."), NATRON_NAMESPACE::WhiteSpaceNormal),
                               this, selRect);
            e->accept();
            return;
        }
    }

    QRectF sceneR = visibleSceneRect();

    bool mustUpdateNavigator = false;
    ///Apply actions
    switch (_imp->_evtState) {
    case eEventStateDraggingArrow: {
        QPointF np = _imp->_arrowSelected->mapFromScene(newPos);
        if ( _imp->_arrowSelected->isOutputEdge() ) {
            _imp->_arrowSelected->dragDest(np);
        } else {
            _imp->_arrowSelected->dragSource(np);
        }
        checkAndStartAutoScrollTimer(newPos);
        mustUpdate = true;
        if (_imp->cursorSet) {
            _imp->cursorSet = false;
            unsetCursor();
        }
        break;
    }
    case eEventStateDraggingNode: {
        mustUpdate = true;
        mustUpdateNavigator = true;
        bool controlDown = modifierHasControl(e);
        bool shiftdown = modifierHasShift(e);
        moveSelectedNodesBy(shiftdown, controlDown, lastMousePosScene, newPos, sceneR, true);
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::ClosedHandCursor) );
        break;
    }
    case eEventStateMovingArea: {
        mustUpdateNavigator = true;
        moveRootInternal(dx, dy);
        mustUpdate = true;
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::SizeAllCursor) );
        break;
    }
    case eEventStateResizingBackdrop: {
        mustUpdateNavigator = true;
        assert(_imp->_backdropResized.lock());
        QPointF p = _imp->_backdropResized.lock()->scenePos();
        int w = newPos.x() - p.x();
        int h = newPos.y() - p.y();
        checkAndStartAutoScrollTimer(newPos);
        mustUpdate = true;
        pushUndoCommand( new ResizeBackdropCommand(_imp->_backdropResized.lock(), w, h) );
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::SizeFDiagCursor) );
        break;
    }
    case eEventStateSelectionRect: {
        QPointF startDrag = _imp->_lastSelectionStartPointScene;
        QPointF cur = newPos;
        double xmin = std::min( cur.x(), startDrag.x() );
        double xmax = std::max( cur.x(), startDrag.x() );
        double ymin = std::min( cur.y(), startDrag.y() );
        double ymax = std::max( cur.y(), startDrag.y() );
        checkAndStartAutoScrollTimer(newPos);
        QRectF selRect(xmin, ymin, xmax - xmin, ymax - ymin);
        _imp->_selectionRect = selRect;
        mustUpdate = true;
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::CrossCursor) );
        break;
    }
    case eEventStateDraggingNavigator: {
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::ClosedHandCursor) );
        QPointF mousePosSceneCoordinates;
        bool insideNavigator = isNearbyNavigator(e->pos(), mousePosSceneCoordinates);
        if (insideNavigator) {
            _imp->_refreshOverlays = true;
            centerOn(mousePosSceneCoordinates);
            _imp->_lastMousePos = e->pos();
            update();

            return;
        }
        break;
    }
    case eEventStateZoomingArea: {
        int delta = 2 * ( ( e->x() - _imp->_lastMousePos.x() ) - ( e->y() - _imp->_lastMousePos.y() ) );
        setTransformationAnchor(QGraphicsView::AnchorViewCenter);
        wheelEventInternal(modCASIsControl(e), delta);
        setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
        mustUpdate = true;
        _imp->cursorSet = true;
        setCursor( QCursor(Qt::SizeAllCursor) );
        break;
    }
    case eEventStateNone:
    default: {
        mustUpdate = false;
        // Test if mouse is inside the navigator
        QPointF mousePosSceneCoordinates;
        bool insideNavigator = isNearbyNavigator(e->pos(), mousePosSceneCoordinates);
        if (insideNavigator) {
            _imp->cursorSet = true;
            setCursor( QCursor(Qt::OpenHandCursor) );
        } else if (!groupEdited) {
            if (_imp->cursorSet) {
                _imp->cursorSet = false;
                unsetCursor();
            }
        } else {
            // Set cursor
            // The cursor should clearly indicate when will happen if mouse is pressed
            NodeGuiPtr nearbyNode;
            Edge* nearbyEdge = NULL;
            NearbyItemEnum nearbyItemCode = hasItemNearbyMouse(e->pos(), &nearbyNode, &nearbyEdge);

            switch (nearbyItemCode) {
            case eNearbyItemNode:
            case eNearbyItemBackdropFrame:
            case eNearbyItemEdgeBendPoint: {
                _imp->cursorSet = true;
                setCursor( QCursor(Qt::OpenHandCursor) );
                break;
            }
            case eNearbyItemBackdropResizeHandle: {
                _imp->cursorSet = true;
                setCursor( QCursor(Qt::SizeFDiagCursor) );
                break;
            }
            case eNearbyItemNone: {
                _imp->cursorSet = true;
                setCursor( QCursor(Qt::CrossCursor) );
                break;
            }
            case eNearbyItemNodeEdge:
            default: {
                if (_imp->cursorSet) {
                    _imp->cursorSet = false;
                    unsetCursor();
                }
                break;
            }
            }
        }
        break;
    }
    } // switch


    _imp->_lastMousePos = e->pos();


    if (mustUpdateNavigator) {
        _imp->_refreshOverlays = true;
        mustUpdate = true;
    }

    if (mustUpdate) {
        update();
    }

    TabWidget* tab = getParentPane() ;
    if (tab && _imp->_evtState == eEventStateNone) {
        // If the Viewer is in a tab, send the tab widget the event directly
        qApp->sendEvent(tab, e);
    }
    QGraphicsView::mouseMoveEvent(e);
} // mouseMoveEvent
Esempio n. 3
0
void
NodeGraph::moveSelectedNodesBy(bool shiftdown,
                               bool controlDown,
                               const QPointF& lastMousePosScene,
                               const QPointF& newPos,
                               const QRectF& visibleSceneR,
                               bool userEdit)
{
    if ( _imp->_selection.empty() ) {
        return;
    }


    //Get the nodes to move, taking into account the backdrops
    std::list<std::pair<NodeGuiPtr, bool> > nodesToMove;
    for (NodesGuiList::iterator it = _imp->_selection.begin();
            it != _imp->_selection.end(); ++it) {
        const NodeGuiPtr& node = *it;
        nodesToMove.push_back( std::make_pair(node, false) );

        std::map<NodeGuiPtr, NodesGuiList>::iterator foundBd = _imp->_nodesWithinBDAtPenDown.find(*it);
        if ( !controlDown && ( foundBd != _imp->_nodesWithinBDAtPenDown.end() ) ) {
            for (NodesGuiList::iterator it2 = foundBd->second.begin();
                    it2 != foundBd->second.end(); ++it2) {
                ///add it only if it's not already in the list
                bool found = false;
                for (std::list<std::pair<NodeGuiPtr, bool> >::iterator it3 = nodesToMove.begin();
                        it3 != nodesToMove.end(); ++it3) {
                    if (it3->first == *it2) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    nodesToMove.push_back( std::make_pair(*it2, true) );
                }
            }
        }
    }

    //The delta
    double dxScene = newPos.x() - lastMousePosScene.x();
    double dyScene = newPos.y() - lastMousePosScene.y();


    //Move all nodes
    bool deltaSet = false;
    for (std::list<std::pair<NodeGuiPtr, bool> >::iterator it = nodesToMove.begin();
            it != nodesToMove.end(); ++it) {
        //The current position
        QPointF pos = it->first->getPos_mt_safe();

        //if ignoreMagnet == true, we do not snap nodes to horizontal/vertical positions
        bool ignoreMagnet = it->second || nodesToMove.size() > 1;
        it->first->refreshPosition(pos.x() + dxScene, pos.y() + dyScene, ignoreMagnet, newPos);

        //The new position
        QPointF newNodePos = it->first->getPos_mt_safe();
        if (!ignoreMagnet) {
            //Magnet only works when selection is only for a single node
            //Adjust the delta since mouse press by the new position after snapping
            assert(nodesToMove.size() == 1);
            _imp->_deltaSinceMousePress.rx() += newNodePos.x() - pos.x();
            _imp->_deltaSinceMousePress.ry() += newNodePos.y() - pos.y();
            deltaSet = true;
        }
    }

    if (!deltaSet) {
        _imp->_deltaSinceMousePress.rx() += dxScene;
        _imp->_deltaSinceMousePress.ry() += dyScene;
    }

    if (!userEdit) {
        //For !userEdit do not do auto-scroll and connections hints
        return;
    }

    //Start auto-scolling if nearby the edges
    checkAndStartAutoScrollTimer(newPos);

    //Set the hand cursor
    _imp->cursorSet = true;
    setCursor(Qt::ClosedHandCursor);

    //The lines below are trying to
    if (_imp->_selection.size() != 1) {
        return;
    }

    checkForHints(shiftdown, controlDown, _imp->_selection.front(), visibleSceneR);
} // NodeGraph::moveSelectedNodesBy
Esempio n. 4
0
void
NodeGraph::moveSelectedNodesBy(bool shiftdown,
                               bool controlDown,
                               const QPointF& lastMousePosScene,
                               const QPointF& newPos,
                               const QRectF& visibleSceneR,
                               bool userEdit)
{
    if ( _imp->_selection.empty() ) {
        return;
    }


    //Get the nodes to move, taking into account the backdrops
    bool ignoreMagnet = false;
    std::set<NodeGuiPtr> nodesToMove;
    for (NodesGuiWList::iterator it = _imp->_selection.begin();
         it != _imp->_selection.end(); ++it) {
        NodeGuiPtr node = it->lock();
        if (!node) {
            continue;
        }
        nodesToMove.insert(node);

        std::map<NodeGuiPtr, NodesGuiList>::iterator foundBd = _imp->_nodesWithinBDAtPenDown.find(node);
        if ( !controlDown && ( foundBd != _imp->_nodesWithinBDAtPenDown.end() ) ) {
            ignoreMagnet = true; // we move a backdrop, ignore magnet
            for (NodesGuiList::iterator it2 = foundBd->second.begin();
                 it2 != foundBd->second.end(); ++it2) {
                ///add it only if it's not already in the list
                nodesToMove.insert(*it2);

            }
        }
    }

    if (!ignoreMagnet && nodesToMove.size() > 1) {
        ignoreMagnet = true;
    }

    //The delta
    double dxScene = newPos.x() - lastMousePosScene.x();
    double dyScene = newPos.y() - lastMousePosScene.y();


    //Move all nodes
    bool deltaSet = false;
    for (std::set<NodeGuiPtr>::iterator it = nodesToMove.begin();
         it != nodesToMove.end(); ++it) {
        //The current position
        QPointF pos = (*it)->pos();

        //if ignoreMagnet == true, we do not snap nodes to horizontal/vertical positions
        (*it)->refreshPosition(pos.x() + dxScene, pos.y() + dyScene, ignoreMagnet, newPos);

        //The new position
        QPointF newNodePos = (*it)->pos();
        if (!ignoreMagnet) {
            //Magnet only works when selection is only for a single node
            //Adjust the delta since mouse press by the new position after snapping
            assert(nodesToMove.size() == 1);
            _imp->_deltaSinceMousePress.rx() += newNodePos.x() - pos.x();
            _imp->_deltaSinceMousePress.ry() += newNodePos.y() - pos.y();
            deltaSet = true;
        }
    }

    if (!deltaSet) {
        _imp->_deltaSinceMousePress.rx() += dxScene;
        _imp->_deltaSinceMousePress.ry() += dyScene;
    }

    if (!userEdit) {
        //For !userEdit do not do auto-scroll and connections hints
        return;
    }

    //Start auto-scolling if nearby the edges
    checkAndStartAutoScrollTimer(newPos);

    //The lines below are trying to
    if (_imp->_selection.size() != 1) {
        return;
    }

    checkForHints(shiftdown, controlDown, _imp->_selection.front().lock(), visibleSceneR);
} // NodeGraph::moveSelectedNodesBy