def dragObject(self):

        if not self.selectedIndexes():
            return

        item = self.selectedItems()[0]
        role = item.data(0, QtCore.Qt.UserRole)

        if role == 'Folder':
            return

        text = 'BeamComponent:' + role

        mimeData = QtCore.QMimeData()
        mimeData.setText(text)

        drag = QtGui.QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(QtCore.QPoint(90, 23))

        ghostComponent = QtGui.QPixmap(180, 46)
        #ghostComponent.fill(QtGui.QColor(67, 143, 153, 80))
        ghostComponent.fill (QtGui.QColor (255, 255, 255, 255))

        drag.setPixmap(ghostComponent)
        drag.start(QtCore.Qt.IgnoreAction)
Exemple #2
0
class KColorWidget(QtWidgets.QLabel):
    """Custom Label widget to display color settings."""

    clicked = QtCore.Signal(bool)
    colorChanged = QtCore.Signal(QtGui.QColor)

    def __init__(self, parent, color):
        super(KColorWidget, self).__init__(parent)
        self.installEventFilter(self)
        self._color = QtGui.QColor(color)

        self.pixmap = QtGui.QPixmap(12, 12)
        self.pixmap.fill(self._color)

        self.setProperty('colorLabel', True)
        self.setFixedSize(24, 24)
        self.setScaledContents(True)
        self.setPixmap(self.pixmap)

        self.createConnections()

    def createConnections(self):
        self.clicked.connect(self.openColorDialog)
        self.colorChanged.connect(self.changeColor)

    def eventFilter(self, object, event):
        if event.type() == QtCore.QEvent.Enter:
            self.setCursor(QtCore.Qt.PointingHandCursor)
            return True

        if event.type() == QtCore.QEvent.Leave:
            self.setCursor(QtCore.Qt.ArrowCursor)
            return True

        if event.type() == QtCore.QEvent.MouseButtonPress:
            self.setCursor(QtCore.Qt.ClosedHandCursor)
            return True

        if event.type() == QtCore.QEvent.MouseButtonRelease:
            self.setCursor(QtCore.Qt.PointingHandCursor)
            self.clicked.emit(True)
            return True

        return False

    def openColorDialog(self):

        colorDialog = QtWidgets.QColorDialog()
        colorDialog.setOption(QtWidgets.QColorDialog.DontUseNativeDialog, True)
        newColor = colorDialog.getColor(self._color, self)
        if newColor.isValid():
            self._color = newColor
            self.colorChanged.emit(newColor)

    def changeColor(self, color):
        self.pixmap.fill(color)
        self.setPixmap(self.pixmap)
Exemple #3
0
 def setDragPoint(self, dragPoint):
     topLeft = QtCore.QPointF(self.__mouseDownPos)
     bottomRight = QtCore.QPointF(dragPoint)
     if dragPoint.x() < self.__mouseDownPos.x():
         topLeft.setX(dragPoint.x())
         bottomRight.setX(self.__mouseDownPos.x())
     if dragPoint.y() < self.__mouseDownPos.y():
         topLeft.setY(dragPoint.y())
         bottomRight.setY(self.__mouseDownPos.y())
     self.setPos(topLeft)
     self.resize(bottomRight.x() - topLeft.x(),
                 bottomRight.y() - topLeft.y())
Exemple #4
0
    def drawBackground(self, painter, rect):

        oldTransform = painter.transform()
        painter.fillRect(rect, self._backgroundColor)

        left = int(rect.left()) - (int(rect.left()) % self._gridSizeFine)
        top = int(rect.top()) - (int(rect.top()) % self._gridSizeFine)

        # Draw horizontal fine lines
        gridLines = []
        painter.setPen(self._gridPenS)
        y = float(top)
        while y < float(rect.bottom()):
            gridLines.append(QtCore.QLineF(rect.left(), y, rect.right(), y))
            y += self._gridSizeFine
        painter.drawLines(gridLines)

        # Draw vertical fine lines
        gridLines = []
        painter.setPen(self._gridPenS)
        x = float(left)
        while x < float(rect.right()):
            gridLines.append(QtCore.QLineF(x, rect.top(), x, rect.bottom()))
            x += self._gridSizeFine
        painter.drawLines(gridLines)

        # Draw thick grid
        left = int(rect.left()) - (int(rect.left()) % self._gridSizeCourse)
        top = int(rect.top()) - (int(rect.top()) % self._gridSizeCourse)

        # Draw vertical thick lines
        gridLines = []
        painter.setPen(self._gridPenL)
        x = left
        while x < rect.right():
            gridLines.append(QtCore.QLineF(x, rect.top(), x, rect.bottom()))
            x += self._gridSizeCourse
        painter.drawLines(gridLines)

        # Draw horizontal thick lines
        gridLines = []
        painter.setPen(self._gridPenL)
        y = top
        while y < rect.bottom():
            gridLines.append(QtCore.QLineF(rect.left(), y, rect.right(), y))
            y += self._gridSizeCourse
        painter.drawLines(gridLines)

        return super(GraphView, self).drawBackground(painter, rect)
Exemple #5
0
    def paint(self, painter, option, widget):
        srcPoint = self.mapFromScene(self.__srcPortCircle.centerInSceneCoords())
        dstPoint = self.mapFromScene(self.__dstPortCircle.centerInSceneCoords())

        dist_between = dstPoint - srcPoint

        self.__path = QtGui.QPainterPath()
        self.__path.moveTo(srcPoint)
        self.__path.cubicTo(
            srcPoint + QtCore.QPointF(dist_between.x() * 0.4, 0),
            dstPoint - QtCore.QPointF(dist_between.x() * 0.4, 0),
            dstPoint
            )
        self.setPath(self.__path)
        super(Connection, self).paint(painter, option, widget)
Exemple #6
0
    def getSelectedNodesCentroid(self):
        selectedNodes = self.getSelectedNodes()

        leftMostNode = None
        topMostNode = None
        for node in selectedNodes:
            nodePos = node.getGraphPos()

            if leftMostNode is None:
                leftMostNode = node
            else:
                if nodePos.x() < leftMostNode.getGraphPos().x():
                    leftMostNode = node

            if topMostNode is None:
                topMostNode = node
            else:
                if nodePos.y() < topMostNode.getGraphPos().y():
                    topMostNode = node

        xPos = leftMostNode.getGraphPos().x()
        yPos = topMostNode.getGraphPos().y()
        pos = QtCore.QPoint(xPos, yPos)

        return pos
Exemple #7
0
class GraphView (QtWidgets.QGraphicsView):
    nodeAdded = QtCore.Signal (Node)

    def __init__ (self, parent = None):
        super (GraphView, self).__init__ (parent)

        self.setObjectName ('graphView')
        self.setRenderHint (QtGui.QPainter.Antialiasing)
        self.setRenderHint (QtGui.QPainter.TextAntialiasing)

        self.setHorizontalScrollBarPolicy (QtCore.Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy (QtCore.Qt.ScrollBarAlwaysOff)

        size = QtCore.QSize (600, 400)
        self.resize (size)
        self.setSceneRect (-size.width () * 0.5, -size.height () * 0.5, size.width (), size.height ())
        self.setAcceptDrops (True)
        self.reset()

    def reset(self):
        self.setScene(QtWidgets.QGraphicsScene())

    def addNode (self, node, emitSignal = True):
        self.scene ().addItem (node)

        if emitSignal:
            self.nodeAdded.emit (node)

        return node
Exemple #8
0
    def __init__(self, port, graph, hOffset, color, connectionPointType):
        super(PortCircle, self).__init__(port)

        self.__port = port
        self._graph = graph
        self._connectionPointType = connectionPointType
        self.__connections = set()
        self._supportsOnlySingleConnections = connectionPointType == 'In'

        self.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed))
        size = QtCore.QSizeF(self.__diameter, self.__diameter)
        self.setPreferredSize(size)
        self.setWindowFrameMargins(0, 0, 0, 0)

        self.transform().translate(self.__radius * hOffset, 0)

        self.__defaultPen = QtGui.QPen(QtGui.QColor(25, 25, 25), 1.0)
        self.__hoverPen = QtGui.QPen(QtGui.QColor(255, 255, 100), 1.5)

        self._ellipseItem = QtWidgets.QGraphicsEllipseItem(self)
        self._ellipseItem.setPen(self.__defaultPen)
        self._ellipseItem.setPos(size.width()/2, size.height()/2)
        self._ellipseItem.setRect(
            -self.__radius,
            -self.__radius,
            self.__diameter,
            self.__diameter,
            )
        if connectionPointType == 'In':
            self._ellipseItem.setStartAngle(270 * 16)
            self._ellipseItem.setSpanAngle(180 * 16)

        self.setColor(color)
        self.setAcceptHoverEvents(True)
Exemple #9
0
    def __init__(self, graph, component):
        super(KNode, self).__init__(graph, component.getDecoratedName())

        self.__component = component
        self.__inspectorWidget = None

        print "KNode.__component.getNumInputs(): %s"%(self.__component.getNumInputs())
        for i in range(self.__component.getNumInputs()):
            componentInput = component.getInputByIndex(i)
            print "KNode.componentInput: %s"%(componentInput)
            self.addPort(KNodeInputPort(self, graph, componentInput))

        print "KNode.__component.getNumOutputs(): %s" % (self.__component.getNumOutputs ())
        for i in range(self.__component.getNumOutputs()):
            componentOutput = component.getOutputByIndex(i)
            self.addPort(KNodeOutputPort(self, graph, componentOutput))

        self.setGraphPos( QtCore.QPointF( self.__component.getGraphPos().x, self.__component.getGraphPos().y ) )
        #self.setGraphPos (QtCore.QPointF (1, 1))

        nodeColor = component.getComponentColor()
        print "KNode.nodeColor: ",(nodeColor)
        self.setColor(QtGui.QColor(nodeColor[0], nodeColor[1], nodeColor[2], nodeColor[3]))
        self.setUnselectedColor(self.getColor().darker(125))
        self.setSelectedColor(self.getColor().lighter(175))
Exemple #10
0
class Node (QtWidgets.QGraphicsWidget):
    nameChanged = QtCore.Signal (str, str)

    __defaultColor = QtGui.QColor (154, 205, 50, 255)
    __defaultUnselectedColor = QtGui.QColor (25, 25, 25)
    __defaultSelectedColor = QtGui.QColor (255, 255, 255, 255)

    __defaultUnselectedPen = QtGui.QPen (__defaultUnselectedColor, 1.6)
    __defaultSelectedPen = QtGui.QPen (__defaultSelectedColor, 1.6)
    __defaultLinePen = QtGui.QPen (QtGui.QColor (25, 25, 25, 255), 1.25)

    def __init__ (self):
        super (Node, self).__init__ ()

        self.__color = self.__defaultColor
        self.__unselectedColor = self.__defaultUnselectedColor
        self.__selectedColor = self.__defaultSelectedColor

        self.__unselectedPen = QtGui.QPen (self.__defaultUnselectedPen)
        self.__selectedPen = QtGui.QPen (self.__defaultSelectedPen)
        self.__linePen = QtGui.QPen (self.__defaultLinePen)

        self.setMinimumWidth (60)
        self.setMinimumHeight (20)
        self.setSizePolicy (QtWidgets.QSizePolicy (QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding))

        layout = QtWidgets.QGraphicsLinearLayout ()
        layout.setContentsMargins (0, 0, 0, 0)
        layout.setSpacing (0)
        layout.setOrientation (QtCore.Qt.Vertical)
        self.setLayout (layout)

        self.__headerItem = NodeHeader ("xxx", self)
        layout.addItem (self.__headerItem)
        layout.setAlignment (self.__headerItem, QtCore.Qt.AlignCenter | QtCore.Qt.AlignTop)

        self.__ports = []
        self.__inputPortsHolder = PortList (self)
        self.__ioPortsHolder = PortList (self)
        self.__outputPortsHolder = PortList (self)

        layout.addItem (self.__inputPortsHolder)
        layout.addItem (self.__ioPortsHolder)
        layout.addItem (self.__outputPortsHolder)

        self.__selected = False
        self.__dragging = False

    def addPort(self, port):
        if isinstance(port, InputPort):
            self.__inputPortsHolder.addPort(port, QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        elif isinstance(port, OutputPort):
            self.__outputPortsHolder.addPort(port, QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        else:
            self.__ioPortsHolder.addPort(port, QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        self.__ports.append(port)

        self.adjustSize()
        return port
Exemple #11
0
class componentMainSettings(QtWidgets.QDialog, guide.helperSlots):
    valueChanged = QtCore.Signal(int)

    def __init__(self, parent=None):
        super(componentMainSettings, self).__init__()
        # the inspectSettings function set the current selection to the
        # component root before open the settings dialog
        self.root = pm.selected()[0]
Exemple #12
0
    def boundingRect(self):
        srcPoint = self.mapFromScene(self.__srcPortCircle.centerInSceneCoords())
        dstPoint = self.mapFromScene(self.__dstPortCircle.centerInSceneCoords())
        penWidth = self.__defaultPen.width()

        return QtCore.QRectF(
            min(srcPoint.x(), dstPoint.x()),
            min(srcPoint.y(), dstPoint.y()),
            abs(dstPoint.x() - srcPoint.x()),
            abs(dstPoint.y() - srcPoint.y()),
            ).adjusted(-penWidth/2, -penWidth/2, +penWidth/2, +penWidth/2)
Exemple #13
0
class RigNameLabel(QtWidgets.QLabel):

    clicked = QtCore.Signal()

    def __init__(self, parent=None):
        super(RigNameLabel, self).__init__(parent)
        self.setObjectName('rigNameLabel')
        self.setToolTip('Double Click to Edit')

    def mouseDoubleClickEvent(self, event):
        self.clicked.emit()
Exemple #14
0
    def __init__(self, parent=None):

        # constructors of base classes
        super(BeamUI, self).__init__(parent)
        self.setObjectName('mainUI')
        self.setWindowIcon(QtGui.QIcon(''))

        self.setWindowTitle("Beam Editor")
        self.setAcceptDrops(True)

        self.mainVboxLayout = QtGui.QVBoxLayout (self)

        self.guideLayout = QtGui.QVBoxLayout ()
        self.mainVboxLayout.addLayout(self.guideLayout)

        self.build_from_selection = QtGui.QPushButton("build_from_selection")
        self.mainVboxLayout.addWidget(self.build_from_selection)

        compDir = shifter.getComponentDirectories ()

        path = self.current_path ()

        trackLoadComponent = []

        for path, comps in compDir.iteritems ():
            for comp_name in comps:

                if comp_name in trackLoadComponent:
                    pm.displayWarning(
                        "Custom component name: %s, already in default "
                        "components. Names should be unique. This component is"
                        " not loaded" % comp_name)
                    continue
                else:
                    trackLoadComponent.append (comp_name)
                if not os.path.exists(os.path.join(path,
                                                   comp_name, "__init__.py")):
                    continue
                module = shifter.importComponentGuide (comp_name)
                print "BeamUI.__init__.module",module
                reload (module)

                commandbutton = self.loadUiWidget (os.path.join (path.replace("beam_components","widgets"), "commandbutton.ui"))

                icon = QtGui.QPixmap(os.path.join (path,module.TYPE,"icon.jpg"))
                self.guideLayout.addWidget (commandbutton)
                commandbutton.pushButton.setText(module.TYPE)
                commandbutton.label.setPixmap (icon)
                QtCore.QObject.connect (commandbutton.pushButton, QtCore.SIGNAL ("clicked()"),
                                        partial (self.drawComp, module.TYPE))

        self.createConnections()
Exemple #15
0
    def __init__ (self, parent = None):
        super (GraphView, self).__init__ (parent)

        self.setObjectName ('graphView')
        self.setRenderHint (QtGui.QPainter.Antialiasing)
        self.setRenderHint (QtGui.QPainter.TextAntialiasing)

        self.setHorizontalScrollBarPolicy (QtCore.Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy (QtCore.Qt.ScrollBarAlwaysOff)

        size = QtCore.QSize (600, 400)
        self.resize (size)
        self.setSceneRect (-size.width () * 0.5, -size.height () * 0.5, size.width (), size.height ())
        self.setAcceptDrops (True)
        self.reset()
Exemple #16
0
    def frameNodes(self, nodes):
        if len(nodes) == 0:
            return

        def computeWindowFrame():
            windowRect = self.rect()
            windowRect.setLeft(windowRect.left() + 16)
            windowRect.setRight(windowRect.right() - 16)
            windowRect.setTop(windowRect.top() + 16)
            windowRect.setBottom(windowRect.bottom() - 16)
            return windowRect

        nodesRect = None
        for node in nodes:
            nodeRectF = node.transform().mapRect(node.rect())
            nodeRect = QtCore.QRect(nodeRectF.x(), nodeRectF.y(),
                                    nodeRectF.width(), nodeRectF.height())
            if nodesRect is None:
                nodesRect = nodeRect
            else:
                nodesRect = nodesRect.united(nodeRect)

        windowRect = computeWindowFrame()

        scaleX = float(windowRect.width()) / float(nodesRect.width())
        scaleY = float(windowRect.height()) / float(nodesRect.height())
        if scaleY > scaleX:
            scale = scaleX
        else:
            scale = scaleY

        if scale < 1.0:
            self.setTransform(QtGui.QTransform.fromScale(scale, scale))
        else:
            self.setTransform(QtGui.QTransform())

        sceneRect = self.sceneRect()
        pan = sceneRect.center() - nodesRect.center()
        sceneRect.translate(-pan.x(), -pan.y())
        self.setSceneRect(sceneRect)

        # Update the main panel when reframing.
        self.update()
Exemple #17
0
    def __init__(self, parent=None):
        super(GraphView, self).__init__(parent)
        self.setObjectName('graphView')

        self.__graphViewWidget = parent

        self.setRenderHint(QtGui.QPainter.Antialiasing)
        self.setRenderHint(QtGui.QPainter.TextAntialiasing)

        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

        # Explicitly set the scene rect. This ensures all view parameters will be explicitly controlled
        # in the event handlers of this class.
        size = QtCore.QSize(600, 400)
        self.resize(size)
        self.setSceneRect(-size.width() * 0.5, -size.height() * 0.5,
                          size.width(), size.height())

        self.setAcceptDrops(True)
        self.reset()
Exemple #18
0
    def mouseMoveEvent(self, event):
        if self.__dragging:
            newPos = self.mapToScene(event.pos())

            graph = self.getGraph()
            if graph.getSnapToGrid() is True:
                gridSize = graph.getGridSize()

                newNodePos = newPos - self._mouseDelta

                snapPosX = math.floor(newNodePos.x() / gridSize) * gridSize
                snapPosY = math.floor(newNodePos.y() / gridSize) * gridSize
                snapPos = QtCore.QPointF(snapPosX, snapPosY)

                newPosOffset = snapPos - newNodePos

                newPos = newPos + newPosOffset

            delta = newPos - self._lastDragPoint
            self.__graph.moveSelectedNodes(delta)
            self._lastDragPoint = newPos
            self._nodesMoved = True
        else:
            super(Node, self).mouseMoveEvent(event)
Exemple #19
0
class GraphViewWidget(QtWidgets.QWidget):

    rigNameChanged = QtCore.Signal()

    def __init__(self, parent=None):

        # constructors of base classes
        super(GraphViewWidget, self).__init__(parent)
        self.openedFile = None
        self.setObjectName('graphViewWidget')
        self.setAttribute(QtCore.Qt.WA_WindowPropagation, True)

    def setGraphView(self, graphView):
        self.graphView = graphView

        # Setup Layout
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.graphView)
        self.setLayout(layout)

        #########################
        ## Setup hotkeys for the following actions.
        deleteShortcut = QtWidgets.QShortcut(
            QtGui.QKeySequence(QtCore.Qt.Key_Delete), self)
        deleteShortcut.activated.connect(self.graphView.deleteSelectedNodes)

        frameShortcut = QtWidgets.QShortcut(
            QtGui.QKeySequence(QtCore.Qt.Key_F), self)
        frameShortcut.activated.connect(self.graphView.frameSelectedNodes)

        frameShortcut = QtWidgets.QShortcut(
            QtGui.QKeySequence(QtCore.Qt.Key_A), self)
        frameShortcut.activated.connect(self.graphView.frameAllNodes)

    def getGraphView(self):
        return self.graphView
Exemple #20
0
 def textSize(self):
     return QtCore.QSizeF(
         self.__fontMetrics.width(self.__text),
         self.__fontMetrics.height()
         )
Exemple #21
0
class UndoRedoManager(QtCore.QObject):
    """An UndoManager manages the undo/redo stack for an application.
    Usually only a single undo manager is instantiated for a given application,
    but it is possible to instantiate multiple undomanagers, each one responsible for a separate undo stack.

    """

    __instance = None
    undoUpdated = QtCore.Signal(object)

    def __init__(self):
        super(UndoRedoManager, self).__init__()
        self.__undoStack = []
        self.__redoStack = []
        self.__currentBracket = None
        self.__isUndoingOrRedoing = False
        self.__enabled = True

        self.__fireUpdateCallback()

    def enable(self):
        """Enables the UndoManager so that new brackets can be opened and commands added"""
        self.__enabled = True

    def disable(self):
        """Disables the UndoManager so that no new brackets can be opened or commands added"""
        self.__enabled = False

    def enabled(self):
        """Returns true if the UndoManager is enabled"""
        return self.__enabled

    def canAddCommand(self):
        """Returns True if the undo manager is in a state where a command can be added.
        A command can only be added if the undo manager is enabled, a bracket has been opened, and the undo manager is not currently undoing or redoing commands.
        """
        return self.__enabled and not self.__isUndoingOrRedoing

    def isUndoingOrRedoing(self):
        """Returns true if the undo manager is currently undoing or redoing."""
        return self.__isUndoingOrRedoing

    def addCommand(self, command, invokeRedoOnAdd=False):
        """
        Adds a new command to the currently opened undo bracket.
        :param command: A command object which encapsulates the revertable action.
        """

        if not self.canAddCommand():
            raise Exception("Cannot add command when undo manager is disabled")

        if self.__currentBracket:
            self.__currentBracket.addCommand(command,
                                             invokeRedoOnAdd=invokeRedoOnAdd)
        else:
            if invokeRedoOnAdd:
                command.redo()
            if len(self.__undoStack) > 0:
                if self.__undoStack[len(self.__undoStack) -
                                    1].mergeWith(command):
                    # the command was merged with the previous, so does not need to be applied separately
                    return

            self.__undoStack.append(command)

        self.__fireUpdateCallback()

    def openBracket(self, desc):
        """Opens a new undo bracket so that subsequent updo commands are added to the new bracket.

        When a command bracket it opened, all subsequent commands are added to the
        command bracket, which will be treated as a single undo on command the stack.
        openBracket can be called multiple times creating nested brackets. For each call to openBracket,
        closeBracket must also be called to ensure the undo manager is left in a valid state.

        :param desc: A string to describe the new bracket. This string can be used to populate undo widgets.
        """

        if not self.canAddCommand():
            raise Exception(
                "Cannot open bracket when undo manager is disabled")

        self.__currentBracket = CommandBracket(desc, self.__currentBracket)

        if not self.__currentBracket.getParentCommandBracket():
            # Append the command if it is a root command bracket.
            self.__undoStack.append(self.__currentBracket)
        self.__clearRedoStack()

        # print ">>>openBracket:" + desc

    def closeBracket(self):
        """
        Closes the currently open undo bracket, encapsulating all added commands into a single undable action.
        If multiple levels of brackets have been opened, the parent bracked is made the current active bracket.
        """
        assert not self.__currentBracket is None, "UndoRedoManager.closeBracket() called but bracket has not been opened"
        # print "<<<closeBracket:" + self.__currentBracket.shortDesc()

        if self.__currentBracket.getNumCommands() == 0:
            print "Warning: UndoBracket closed with no commands added:" + self.__currentBracket.shortDesc(
            )
            if self.__currentBracket.getParentCommandBracket() is not None:
                self.__currentBracket.getParentCommandBracket().popCommand()
            else:
                self.__undoStack.pop()
            # When a bracket is closed, the parent command backet is re-instated.
            self.__currentBracket = self.__currentBracket.getParentCommandBracket(
            )
        else:
            self.__currentBracket.finalize()
            # When a bracket is closed, the parent command backet is re-instated.
            self.__currentBracket = self.__currentBracket.getParentCommandBracket(
            )
            if not self.__currentBracket:
                # Fire the update only if the root level command bracket is closed.
                self.__fireUpdateCallback()

        # import inspect
        # for frame, filename, line_num, func, source_code, source_index in inspect.stack():
        #   print "stack :" + (filename) + ":" + str(func) + ":" + str(source_code)

    def cancelBracket(self):
        """
        Cancels the currently open bracket, reverting all changes added to the bracket since openBracket was called.
        """
        assert not self.__currentBracket is None, "UndoRedoManager.cancelBracket() called but bracket has not been opened"
        #print "<<<closeBracket:" + self.__currentBracket.shortDesc()
        self.closeBracket()
        self.undo()
        command = self.__redoStack.pop()
        command.destroy()
        self.__fireUpdateCallback()
        #

    def bracketOpened(self):
        """Returns True if a bracket has been opened.
        """
        return not self.__currentBracket is None

    def haveUndo(self):
        """Returns Ture if the undo stack currently contains an undoable action"""
        return len(self.__undoStack) > 0

    def canUndo(self):
        """Returns Ture if the undo stack currently contains an undoable action"""
        return self.haveUndo()

    def undo(self):
        """Reverts the action at the top of the undo stack"""
        assert self.haveUndo(
        ), "UndoRedoManager.undo() called but UndoRedoManager.haveUndo() is false"
        self.__isUndoingOrRedoing = True
        command = self.__undoStack.pop()
        command.undo()
        self.__redoStack.append(command)
        self.__fireUpdateCallback()
        self.__isUndoingOrRedoing = False

    def haveRedo(self):
        """Returns Ture if the redo stack currently contains an redoable action"""
        return len(self.__redoStack) > 0

    def canRedo(self):
        """Returns Ture if the redo stack currently contains an redoable action"""
        return self.haveRedo()

    def redo(self):
        """Reapplies the action at the top of the redo stack"""
        self.__isUndoingOrRedoing = True
        command = self.__redoStack.pop()
        command.redo()
        self.__undoStack.append(command)
        self.__fireUpdateCallback()
        self.__isUndoingOrRedoing = False

    def __clearUndoStack(self):
        for command in self.__undoStack:
            command.destroy()
        self.__undoStack = []

    def __clearRedoStack(self):
        for command in self.__redoStack:
            command.destroy()
        self.__redoStack = []

    def reset(self):
        """Resets the undo manager, clearing both the undo and redo stacks"""
        self.__clearUndoStack()
        self.__clearRedoStack()
        self.__fireUpdateCallback()

    def destroy(self):
        """Destroys all data in the undo manager."""
        self.reset()

    def __fireUpdateCallback(self):

        if self.haveUndo():
            undoShortDesc = self.__undoStack[-1].shortDesc()
        else:
            undoShortDesc = None

        if self.haveRedo():
            redoShortDesc = self.__redoStack[-1].shortDesc()
        else:
            redoShortDesc = None

        self.undoUpdated.emit({
            'undoShortDesc': undoShortDesc,
            'canUndo': self.haveUndo(),
            'redoShortDesc': redoShortDesc,
            'canRedo': self.haveRedo()
        })

    def logDebug(self):
        """Prints debug strings to help debug the state of the undo manager"""
        print "bracketOpened:" + str(self.bracketOpened())
        print "undoStack:"
        for command in self.__undoStack:
            command.logDebug(1)
        print "redoStack:"
        for command in self.__redoStack:
            command.logDebug(1)
        print "-------------"

    @classmethod
    def getInstance(cls):
        if cls.__instance is None:
            cls.__instance = UndoRedoManager()
        return cls.__instance
Exemple #22
0
class GraphView(QtWidgets.QGraphicsView):

    nodeAdded = QtCore.Signal(Node)
    nodeRemoved = QtCore.Signal(Node)
    nodeNameChanged = QtCore.Signal(str, str)
    beginDeleteSelection = QtCore.Signal()
    endDeleteSelection = QtCore.Signal()

    beginConnectionManipulation = QtCore.Signal()
    endConnectionManipulation = QtCore.Signal()
    connectionAdded = QtCore.Signal(Connection)
    connectionRemoved = QtCore.Signal(Connection)

    beginNodeSelection = QtCore.Signal()
    endNodeSelection = QtCore.Signal()
    selectionChanged = QtCore.Signal(list, list)

    # During the movement of the nodes, this signal is emitted with the incremental delta.
    selectionMoved = QtCore.Signal(set, QtCore.QPointF)

    # After moving the nodes interactively, this signal is emitted with the final delta.
    endSelectionMoved = QtCore.Signal(set, QtCore.QPointF)

    _clipboardData = None

    _backgroundColor = QtGui.QColor(50, 50, 50)
    _gridPenS = QtGui.QPen(QtGui.QColor(44, 44, 44, 255), 0.5)
    _gridPenL = QtGui.QPen(QtGui.QColor(40, 40, 40, 255), 1.0)
    _gridSizeFine = 30
    _gridSizeCourse = 300

    _mouseWheelZoomRate = 0.0005

    _snapToGrid = False

    def __init__(self, parent=None):
        super(GraphView, self).__init__(parent)
        self.setObjectName('graphView')

        self.__graphViewWidget = parent

        self.setRenderHint(QtGui.QPainter.Antialiasing)
        self.setRenderHint(QtGui.QPainter.TextAntialiasing)

        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

        # Explicitly set the scene rect. This ensures all view parameters will be explicitly controlled
        # in the event handlers of this class.
        size = QtCore.QSize(600, 400)
        self.resize(size)
        self.setSceneRect(-size.width() * 0.5, -size.height() * 0.5,
                          size.width(), size.height())

        self.setAcceptDrops(True)
        self.reset()

    def getGraphViewWidget(self):
        return self.__graphViewWidget

    ################################################
    ## Graph
    def reset(self):
        self.setScene(QtWidgets.QGraphicsScene())

        self.__connections = set()
        self.__nodes = {}
        self.__selection = set()

        self._manipulationMode = MANIP_MODE_NONE
        self._selectionRect = None

    def getGridSize(self):
        """Gets the size of the grid of the graph.

        Returns:
            int: Size of the grid.

        """

        return self._gridSizeFine

    def getSnapToGrid(self):
        """Gets the snap to grid value.

        Returns:
            Boolean: Whether snap to grid is active or not.

        """

        return self._snapToGrid

    def setSnapToGrid(self, snap):
        """Sets the snap to grid value.

        Args:
            snap (Boolean): True to snap to grid, false not to.

        """

        self._snapToGrid = snap

    ################################################
    ## Nodes

    def addNode(self, node, emitSignal=True):
        self.scene().addItem(node)
        self.__nodes[node.getName()] = node
        node.nameChanged.connect(self._onNodeNameChanged)

        if emitSignal:
            self.nodeAdded.emit(node)

        return node

    def removeNode(self, node, emitSignal=True):

        del self.__nodes[node.getName()]
        self.scene().removeItem(node)
        node.nameChanged.disconnect(self._onNodeNameChanged)

        if emitSignal:
            self.nodeRemoved.emit(node)

    def hasNode(self, name):
        return name in self.__nodes

    def getNode(self, name):
        if name in self.__nodes:
            return self.__nodes[name]
        return None

    def getNodes(self):
        return self.__nodes

    def _onNodeNameChanged(self, origName, newName):
        if newName in self.__nodes and self.__nodes[origName] != self.__nodes[
                newName]:
            raise Exception("New name collides with existing node.")
        node = self.__nodes[origName]
        self.__nodes[newName] = node
        del self.__nodes[origName]
        self.nodeNameChanged.emit(origName, newName)

    def clearSelection(self, emitSignal=True):

        prevSelection = []
        if emitSignal:
            for node in self.__selection:
                prevSelection.append(node)

        for node in self.__selection:
            node.setSelected(False)
        self.__selection.clear()

        if emitSignal and len(prevSelection) != 0:
            self.selectionChanged.emit(prevSelection, [])

    def selectNode(self, node, clearSelection=False, emitSignal=True):
        prevSelection = []
        if emitSignal:
            for n in self.__selection:
                prevSelection.append(n)

        if clearSelection is True:
            self.clearSelection(emitSignal=False)

        if node in self.__selection:
            raise IndexError("Node is already in selection!")

        node.setSelected(True)
        self.__selection.add(node)

        if emitSignal:

            newSelection = []
            for n in self.__selection:
                newSelection.append(n)

            self.selectionChanged.emit(prevSelection, newSelection)

    def deselectNode(self, node, emitSignal=True):

        if node not in self.__selection:
            raise IndexError("Node is not in selection!")

        prevSelection = []
        if emitSignal:
            for n in self.__selection:
                prevSelection.append(n)

        node.setSelected(False)
        self.__selection.remove(node)

        if emitSignal:
            newSelection = []
            for n in self.__selection:
                newSelection.append(n)

            self.selectionChanged.emit(prevSelection, newSelection)

    def getSelectedNodes(self):
        return self.__selection

    def deleteSelectedNodes(self):
        self.beginDeleteSelection.emit()

        selectedNodes = self.getSelectedNodes()
        names = ""
        for node in selectedNodes:
            node.disconnectAllPorts()
            self.removeNode(node)

        self.endDeleteSelection.emit()

    def frameNodes(self, nodes):
        if len(nodes) == 0:
            return

        def computeWindowFrame():
            windowRect = self.rect()
            windowRect.setLeft(windowRect.left() + 16)
            windowRect.setRight(windowRect.right() - 16)
            windowRect.setTop(windowRect.top() + 16)
            windowRect.setBottom(windowRect.bottom() - 16)
            return windowRect

        nodesRect = None
        for node in nodes:
            nodeRectF = node.transform().mapRect(node.rect())
            nodeRect = QtCore.QRect(nodeRectF.x(), nodeRectF.y(),
                                    nodeRectF.width(), nodeRectF.height())
            if nodesRect is None:
                nodesRect = nodeRect
            else:
                nodesRect = nodesRect.united(nodeRect)

        windowRect = computeWindowFrame()

        scaleX = float(windowRect.width()) / float(nodesRect.width())
        scaleY = float(windowRect.height()) / float(nodesRect.height())
        if scaleY > scaleX:
            scale = scaleX
        else:
            scale = scaleY

        if scale < 1.0:
            self.setTransform(QtGui.QTransform.fromScale(scale, scale))
        else:
            self.setTransform(QtGui.QTransform())

        sceneRect = self.sceneRect()
        pan = sceneRect.center() - nodesRect.center()
        sceneRect.translate(-pan.x(), -pan.y())
        self.setSceneRect(sceneRect)

        # Update the main panel when reframing.
        self.update()

    def frameSelectedNodes(self):
        self.frameNodes(self.getSelectedNodes())

    def frameAllNodes(self):
        allnodes = []
        for name, node in self.__nodes.iteritems():
            allnodes.append(node)
        self.frameNodes(allnodes)

    def getSelectedNodesCentroid(self):
        selectedNodes = self.getSelectedNodes()

        leftMostNode = None
        topMostNode = None
        for node in selectedNodes:
            nodePos = node.getGraphPos()

            if leftMostNode is None:
                leftMostNode = node
            else:
                if nodePos.x() < leftMostNode.getGraphPos().x():
                    leftMostNode = node

            if topMostNode is None:
                topMostNode = node
            else:
                if nodePos.y() < topMostNode.getGraphPos().y():
                    topMostNode = node

        xPos = leftMostNode.getGraphPos().x()
        yPos = topMostNode.getGraphPos().y()
        pos = QtCore.QPoint(xPos, yPos)

        return pos

    def moveSelectedNodes(self, delta, emitSignal=True):
        for node in self.__selection:
            node.translate(delta.x(), delta.y())

        if emitSignal:
            self.selectionMoved.emit(self.__selection, delta)

            # After moving the nodes interactively, this signal is emitted with the final delta.

    def endMoveSelectedNodes(self, delta):
        self.endSelectionMoved.emit(self.__selection, delta)

    ################################################
    ## Events

    def mousePressEvent(self, event):
        if event.button() is QtCore.Qt.MouseButton.LeftButton and self.itemAt(
                event.pos()) is None:
            self.beginNodeSelection.emit()
            self._manipulationMode = MANIP_MODE_SELECT
            self._mouseDownSelection = copy.copy(self.getSelectedNodes())
            self._selectionRect = SelectionRect(graph=self,
                                                mouseDownPos=self.mapToScene(
                                                    event.pos()))

        elif event.button() is QtCore.Qt.MouseButton.MiddleButton:
            self.setCursor(QtCore.Qt.OpenHandCursor)
            self._manipulationMode = MANIP_MODE_PAN
            self._lastPanPoint = self.mapToScene(event.pos())

        elif event.button() is QtCore.Qt.MouseButton.RightButton:
            self.setCursor(QtCore.Qt.SizeHorCursor)
            self._manipulationMode = MANIP_MODE_ZOOM
            self._lastZoomPoint = self.mapToScene(event.pos())
            self._lastTransform = QtGui.QTransform(self.transform())

        else:
            super(GraphView, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        modifiers = QtWidgets.QApplication.keyboardModifiers()

        if self._manipulationMode == MANIP_MODE_SELECT:
            dragPoint = self.mapToScene(event.pos())
            self._selectionRect.setDragPoint(dragPoint)

            # This logic allows users to use ctrl and shift with rectangle
            # select to add / remove nodes.
            if modifiers == QtCore.Qt.ControlModifier:
                for name, node in self.__nodes.iteritems():

                    if node in self._mouseDownSelection:
                        if node.isSelected(
                        ) and self._selectionRect.collidesWithItem(node):
                            self.deselectNode(node, emitSignal=False)
                        elif not node.isSelected(
                        ) and not self._selectionRect.collidesWithItem(node):
                            self.selectNode(node, emitSignal=False)
                    else:
                        if not node.isSelected(
                        ) and self._selectionRect.collidesWithItem(node):
                            self.selectNode(node, emitSignal=False)
                        elif node.isSelected(
                        ) and not self._selectionRect.collidesWithItem(node):
                            if node not in self._mouseDownSelection:
                                self.deselectNode(node, emitSignal=False)

            elif modifiers == QtCore.Qt.ShiftModifier:
                for name, node in self.__nodes.iteritems():
                    if not node.isSelected(
                    ) and self._selectionRect.collidesWithItem(node):
                        self.selectNode(node, emitSignal=False)
                    elif node.isSelected(
                    ) and not self._selectionRect.collidesWithItem(node):
                        if node not in self._mouseDownSelection:
                            self.deselectNode(node, emitSignal=False)

            else:
                self.clearSelection(emitSignal=False)

                for name, node in self.__nodes.iteritems():
                    if not node.isSelected(
                    ) and self._selectionRect.collidesWithItem(node):
                        self.selectNode(node, emitSignal=False)
                    elif node.isSelected(
                    ) and not self._selectionRect.collidesWithItem(node):
                        self.deselectNode(node, emitSignal=False)

        elif self._manipulationMode == MANIP_MODE_PAN:
            delta = self.mapToScene(event.pos()) - self._lastPanPoint

            rect = self.sceneRect()
            rect.translate(-delta.x(), -delta.y())
            self.setSceneRect(rect)

            self._lastPanPoint = self.mapToScene(event.pos())

        elif self._manipulationMode == MANIP_MODE_MOVE:

            newPos = self.mapToScene(event.pos())
            delta = newPos - self._lastDragPoint
            self._lastDragPoint = newPos

            selectedNodes = self.getSelectedNodes()

            # Apply the delta to each selected node
            for node in selectedNodes:
                node.translate(delta.x(), delta.y())

        elif self._manipulationMode == MANIP_MODE_ZOOM:

            # How much
            delta = event.pos() - self._lastMousePos
            zoomFactor = 1.0
            if delta.x() > 0:
                zoomFactor = 1.0 + delta.x() / 100.0
            else:
                zoomFactor = 1.0 / (1.0 + abs(delta.x()) / 100.0)

            # Limit zoom to 3x
            if self._lastTransform.m22() * zoomFactor >= 2.0:
                return

            # Reset to when we mouse pressed
            self.setSceneRect(self._lastSceneRect)
            self.setTransform(self._lastTransform)

            # Center scene around mouse down
            rect = self.sceneRect()
            rect.translate(self._lastOffsetFromSceneCenter)
            self.setSceneRect(rect)

            # Zoom in (QGraphicsView auto-centers!)
            self.scale(zoomFactor, zoomFactor)

            newSceneCenter = self.sceneRect().center()
            newScenePos = self.mapToScene(self._lastMousePos)
            newOffsetFromSceneCenter = newScenePos - newSceneCenter

            # Put mouse down back where is was on screen
            rect = self.sceneRect()
            rect.translate(-1 * newOffsetFromSceneCenter)
            self.setSceneRect(rect)

            # Call udpate to redraw background
            self.update()

        else:
            super(GraphView, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        if self._manipulationMode == MANIP_MODE_SELECT:

            # If users simply clicks in the empty space, clear selection.
            if self.mapToScene(event.pos()) == self._selectionRect.pos():
                self.clearSelection(emitSignal=False)

            self._selectionRect.destroy()
            self._selectionRect = None
            self._manipulationMode = MANIP_MODE_NONE

            selection = self.getSelectedNodes()

            deselectedNodes = []
            selectedNodes = []

            for node in self._mouseDownSelection:
                if node not in selection:
                    deselectedNodes.append(node)

            for node in selection:
                if node not in self._mouseDownSelection:
                    selectedNodes.append(node)

            if selectedNodes != deselectedNodes:
                self.selectionChanged.emit(deselectedNodes, selectedNodes)

            self.endNodeSelection.emit()

        elif self._manipulationMode == MANIP_MODE_PAN:
            self.setCursor(QtCore.Qt.ArrowCursor)
            self._manipulationMode = MANIP_MODE_NONE

        elif self._manipulationMode == MANIP_MODE_ZOOM:
            self.setCursor(QtCore.Qt.ArrowCursor)
            self._manipulationMode = MANIP_MODE_NONE
            #self.setTransformationAnchor(self._lastAnchor)

        else:
            super(GraphView, self).mouseReleaseEvent(event)

    def wheelEvent(self, event):
        zoomFactor = 1.0 + event.delta() * self._mouseWheelZoomRate

        transform = self.transform()
        # Limit zoom to 3x
        if transform.m22() * zoomFactor >= 2.0:
            return

        sceneCenter = self.sceneRect().center()
        scenePoint = self.mapToScene(event.pos())
        posFromSceneCenter = scenePoint - sceneCenter

        rect = self.sceneRect()
        rect.translate(posFromSceneCenter)
        self.setSceneRect(rect)

        # Zoom in (QGraphicsView auto-centers!)
        self.scale(zoomFactor, zoomFactor)

        # Translate scene back to align original mouse press
        sceneCenter = self.sceneRect().center()
        scenePoint = self.mapToScene(event.pos())
        posFromSceneCenter = scenePoint - sceneCenter

        rect = self.sceneRect()
        posFromSceneCenter *= -1.0
        rect.translate(posFromSceneCenter)
        self.setSceneRect(rect)

        # Call udpate to redraw background
        self.update()

    # =============
    # Copy / Paste
    # =============
    def getClipboardData(self):
        return self.__class__._clipboardData
class ValueController(QtCore.QObject):

    valueChanged = QtCore.Signal(object)
    editableChanged = QtCore.Signal(bool)
    optionChanged = QtCore.Signal(str)

    def __init__(self, name, dataType, editable=True, **kwargs):
        super(ValueController, self).__init__()
        self.name = name
        self.dataType = dataType
        self.editable = editable
        self.options = kwargs

    def getName(self):
        return str(self.name)

    def getDataType(self):
        return self.dataType

    def setValue(self, value):
        command = ValueChangeCommand(self, value)
        UndoRedoManager.getInstance().addCommand(command, invokeRedoOnAdd=True)

    def _setValue_NoUndo(self, value):
        raise NotImplementedError()

    def getValue(self):
        raise NotImplementedError()

    def getOption(self, key, defaultValue=None):
        return self.options.get(key, defaultValue)

    def hasOption(self, key):
        return key in self.options

    def setOption(self, key, value):
        self.options[key] = value
        self.optionChanged.emit(key)

    def isEditable(self):
        return self.editable

    def setEditable(self, editable):
        self.editable = editable
        self.editableChanged.emit(editable)

    def _extractSimpleTypes(self, value):
        if  str(type(value)) == "<type 'PyRTValObject'>" and (
            self.dataType == 'Boolean' or \
            self.dataType == 'UInt8' or \
            self.dataType == 'Byte' or \
            self.dataType == 'SInt8' or \
            self.dataType == 'UInt16' or \
            self.dataType == 'SInt16' or \
            self.dataType == 'UInt32' or \
            self.dataType == 'Count' or \
            self.dataType == 'Index' or \
            self.dataType == 'Size' or \
            self.dataType == 'SInt32' or \
            self.dataType == 'Integer' or \
            self.dataType == 'UInt64' or \
            self.dataType == 'DataSize' or \
            self.dataType == 'SInt64' or \
            self.dataType == 'Float32' or \
            self.dataType == 'Scalar' or \
            self.dataType == 'Float64' or \
            self.dataType == 'String'):
            return value
        else:
            return value

    def emitValueChanged(self):
        self.valueChanged.emit(self.getValue())
class KGraphViewWidget(GraphViewWidget):

    rigNameChanged = QtCore.Signal()

    def __init__(self, parent=None):

        # constructors of base classes
        super(KGraphViewWidget, self).__init__(parent)

        self._builder = None
        self._guideBuilder = None
        self.guideRig = None

        graphView = KGraphView(parent=self)
        self.setGraphView(graphView)
        self.newRigPreset()

    def setGuideRigName(self, text):
        if text.endswith('_guide') is True:
            text = text.replace('_guide', '')

        self.guideRig.setName(text)
        self.rigNameChanged.emit()

    def newRigPreset(self):
        try:
            print "KGraphViewWidget.newRigPreset"
            self.guideRig = Rig()
            graphview = self.getGraphView()
            graphview.displayGraph(self.guideRig)
            self.setGuideRigName('MyRig')

            self.openedFile = None

            self.window().setWindowTitle('Beam Editor')

            print "newRigPreset,New Rig Created"
            #logger.inform("New Rig Created")
        except:
            print "newRigPreset,Error Creating New Rig"
            #logger.exception("Error Creating New Rig")

    def buildGuideRig(self):
        #try:
        self.window().setCursor(QtCore.Qt.WaitCursor)
        initConfigIndex = self.window().beamMenu.configsWidget.currentIndex()
        self.synchGuideRig()

        # Append "_guide" to rig name when building guide
        if self.guideRig.getName().endswith('_guide') is False:
            self.guideRig.setName(self.guideRig.getName() + '_guide')

        if self.window().preferences.getPreferenceValue(
                'delete_existing_rigs'):
            if self._guideBuilder:
                self._guideBuilder.deleteBuildElements()
        self._guideBuilder = plugins.getBuilder()
        self._guideBuilder.build(self.guideRig)

        self.window().beamMenu.setCurrentConfig(initConfigIndex)
        #except:
        #    pass
        #finally:
        print "buildGuideRig.buildGuideRig"
        self.window().setCursor(QtCore.Qt.ArrowCursor)

    def buildRig(self):
        print "buildRig"

    def synchGuideRig(self):
        synchronizer = plugins.getSynchronizer()

        # Guide is always  built with "_guide" need this so synchronizer not confused with real Rig nodes
        if self.guideRig.getName().endswith('_guide') is False:
            self.guideRig.setName(self.guideRig.getName() + '_guide')

        synchronizer.setTarget(self.guideRig)
        synchronizer.sync()
        print "synchGuideRig.synchronizer: ", synchronizer

    # ==============
    # Other Methods
    # ==============
    def addBackdrop(self, name='Backdrop'):
        graphView = self.getGraphView()

        initName = name
        suffix = 1
        collision = True
        while collision:

            collision = graphView.hasNode(name)
            if not collision:
                break

            result = re.split(r"(\d+)$", initName, 1)
            if len(result) > 1:
                initName = result[0]
                suffix = int(result[1])

            name = initName + str(suffix).zfill(2)
            suffix += 1

        backdropNode = KBackdrop(graphView, name)
        graphView.addNode(backdropNode)

        graphView.selectNode(backdropNode, clearSelection=True)

        return backdropNode
Exemple #25
0
 def textSize(self):
     return QtCore.QSizeF(
         self.__textItem.textWidth(),
         self.__font.pointSizeF() + self.__labelBottomSpacing)
Exemple #26
0
class KGraphView(GraphView):

    beginCopyData = QtCore.Signal()
    endCopyData = QtCore.Signal()

    beginPasteData = QtCore.Signal()
    endPasteData = QtCore.Signal()

    _clipboardData = None

    def __init__(self, parent=None):
        super(KGraphView, self).__init__(parent)

        self.__rig = None
        self.setAcceptDrops(True)

    def getRig(self):
        return self.__rig

    # ======
    # Graph
    # ======
    def displayGraph(self, rig):
        print "KGraphView.displayGraph"

        self.reset()
        self.__rig = rig

        guideComponents = self.__rig.getChildrenByType('Component')

        for component in guideComponents:
            node = KNode(self, component)
            self.addNode(node)

    # =======
    # Events
    # =======
    def mousePressEvent(self, event):
        print "KGraphView: mousePressEvent"
        modifiers = QtWidgets.QApplication.keyboardModifiers()

        if event.button() == QtCore.Qt.MouseButton.RightButton:
            print "KGraphView: mousePressEvent.RightButton"
            zoom_with_alt_rmb = self.window().preferences.getPreferenceValue(
                'zoom_with_alt_rmb')
            if zoom_with_alt_rmb and modifiers == QtCore.Qt.AltModifier:
                self._manipulationMode = MANIP_MODE_ZOOM
                self.setCursor(QtCore.Qt.SizeHorCursor)
                self._lastMousePos = event.pos()
                self._lastTransform = QtGui.QTransform(self.transform())
                self._lastSceneRect = self.sceneRect()
                self._lastSceneCenter = self._lastSceneRect.center()
                self._lastScenePos = self.mapToScene(event.pos())
                self._lastOffsetFromSceneCenter = self._lastScenePos - self._lastSceneCenter
                return

            def graphItemAt(item):
                if isinstance(item, KNode):
                    return item
                if isinstance(item, Connection):
                    return item
                elif item is not None:
                    return graphItemAt(item.parentItem())
                return None

            graphicItem = graphItemAt(self.itemAt(event.pos()))
            pos = self.mapToScene(event.pos())

            if graphicItem is None:

                contextMenu = QtWidgets.QMenu(self.getGraphViewWidget())
                contextMenu.setObjectName('rightClickContextMenu')
                contextMenu.setMinimumWidth(150)

                if self.getClipboardData() is not None:

                    def pasteSettings():
                        self.pasteSettings(pos)

                    def pasteSettingsMirrored():
                        self.pasteSettings(pos, mirrored=True)

                    contextMenu.addAction("Paste").triggered.connect(
                        pasteSettings)
                    contextMenu.addAction("Paste Mirrored").triggered.connect(
                        pasteSettingsMirrored)
                    contextMenu.addSeparator()

                graphViewWidget = self.getGraphViewWidget()
                contextMenu.addAction("Add Backdrop").triggered.connect(
                    graphViewWidget.addBackdrop)
                contextMenu.popup(event.globalPos())

            if isinstance(graphicItem, KNode):
                self.selectNode(graphicItem,
                                clearSelection=True,
                                emitSignal=True)

                contextMenu = QtWidgets.QMenu(self.getGraphViewWidget())
                contextMenu.setObjectName('rightClickContextMenu')
                contextMenu.setMinimumWidth(150)

                def copySettings():
                    self.copySettings(pos)

                contextMenu.addAction("Copy").triggered.connect(copySettings)

                if self.getClipboardData() is not None:

                    def pasteSettings():
                        # Paste the settings, not modifying the location, because that will be used to determine symmetry.
                        pasteData = self.getClipboardData()['components'][0]
                        pasteData.pop('graphPos', None)

                        graphicItem.getComponent().pasteData(pasteData,
                                                             setLocation=False)

                    contextMenu.addSeparator()
                    contextMenu.addAction("Paste Data").triggered.connect(
                        pasteSettings)

                contextMenu.popup(event.globalPos())

            elif isinstance(graphicItem, Connection):

                outPort = graphicItem.getSrcPortCircle().getPort()
                inPort = graphicItem.getDstPortCircle().getPort()
                if outPort.getDataType() != inPort.getDataType():

                    if outPort.getDataType().startswith(inPort.getDataType(
                    )) and outPort.getDataType().endswith('[]'):

                        globalPos = event.globalPos()
                        contextMenu = QtWidgets.QMenu(
                            self.getGraphViewWidget())
                        contextMenu.setObjectName('rightClickContextMenu')
                        contextMenu.setMinimumWidth(150)

                        def editIndex():
                            componentInput = graphicItem.getDstPortCircle(
                            ).getPort().getComponentInput()
                            EditIndexWidget(componentInput,
                                            pos=globalPos,
                                            parent=self.getGraphViewWidget())

                        contextMenu.addAction("EditIndex").triggered.connect(
                            editIndex)
                        contextMenu.popup(globalPos)

        elif event.button(
        ) is QtCore.Qt.MouseButton.LeftButton and self.itemAt(
                event.pos()) is None:
            print "KGraphView: mousePressEvent.LeftButton"
            self.beginNodeSelection.emit()
            self._manipulationMode = MANIP_MODE_SELECT
            self._mouseDownSelection = copy.copy(self.getSelectedNodes())
            self._selectionRect = SelectionRect(graph=self,
                                                mouseDownPos=self.mapToScene(
                                                    event.pos()))

        elif event.button() is QtCore.Qt.MouseButton.MiddleButton:
            print "KGraphView: mousePressEvent.MiddleButton"
            pan_with_alt = self.window().preferences.getPreferenceValue(
                'pan_with_alt')
            if pan_with_alt is True and modifiers != QtCore.Qt.AltModifier:
                return

            self.setCursor(QtCore.Qt.OpenHandCursor)
            self._manipulationMode = MANIP_MODE_PAN
            self._lastPanPoint = self.mapToScene(event.pos())

        else:
            super(GraphView, self).mousePressEvent(event)

    def dragEnterEvent(self, event):
        print "KGraphView: dragEnterEvent"
        textParts = event.mimeData().text().split(':')
        if textParts[0] == 'BeamComponent':
            event.accept()
        else:
            event.setDropAction(QtCore.Qt.IgnoreAction)
            super(GraphView, self).dragEnterEvent(event)

    def dragMoveEvent(self, event):
        print "KGraphView: dragMoveEvent"
        super(GraphView, self).dragMoveEvent(event)
        event.accept()

    def dropEvent(self, event):
        print "KGraphView: dropEvent"
        textParts = event.mimeData().text().split(':')
        print "dropEvent.textParts :%s" % (textParts)
        if textParts[0] == 'BeamComponent':
            componentClassName = textParts[1]

            # Add a component to the rig placed at the given position.
            dropPosition = self.mapToScene(event.pos())

            # construct the node and add it to the graph.
            beamSystem = BeamSystem.getInstance()
            componentClass = beamSystem.getComponentClass(componentClassName)
            component = componentClass(parent=self.getRig())
            component.setGraphPos(Vec2(dropPosition.x(), dropPosition.y()))
            node = KNode(self, component)
            self.addNode(node)

            self.selectNode(node, clearSelection=True, emitSignal=False)

            event.acceptProposedAction()
        else:
            super(GraphView, self).dropEvent(event)

    def wheelEvent(self, event):
        print "KGraphView: wheelEvent"
        zoom_mouse_scroll = self.window().preferences.getPreferenceValue(
            'zoom_mouse_scroll')
        if zoom_mouse_scroll is True:
            super(KGraphView, self).wheelEvent(event)

# =============
# Copy / Paste
# =============

    def getClipboardData(self):
        return self.__class__._clipboardData

    def copySettings(self, pos):
        clipboardData = {}

        copiedComponents = []
        nodes = self.getSelectedNodes()
        for node in nodes:
            copiedComponents.append(node.getComponent())

        componentsJson = []
        connectionsJson = []
        for component in copiedComponents:
            componentsJson.append(component.copyData())

            for i in range(component.getNumInputs()):
                componentInput = component.getInputByIndex(i)
                if componentInput.isConnected():
                    componentOutput = componentInput.getConnection()
                    connectionJson = {
                        'source':
                        componentOutput.getParent().getDecoratedName() + '.' +
                        componentOutput.getName(),
                        'target':
                        component.getDecoratedName() + '.' +
                        componentInput.getName()
                    }

                    connectionsJson.append(connectionJson)

        clipboardData = {
            'components': componentsJson,
            'connections': connectionsJson,
            'copyPos': pos
        }

        self.__class__._clipboardData = clipboardData

    def pasteSettings(self,
                      pos,
                      mirrored=False,
                      createConnectionsToExistingNodes=True):

        clipboardData = self.__class__._clipboardData

        krakenSystem = BeamSystem.getInstance()
        delta = pos - clipboardData['copyPos']
        self.clearSelection()
        pastedComponents = {}
        nameMapping = {}

        for componentData in clipboardData['components']:
            componentClass = krakenSystem.getComponentClass(
                componentData['class'])
            component = componentClass(parent=self.__rig)
            decoratedName = componentData[
                'name'] + component.getNameDecoration()
            nameMapping[decoratedName] = decoratedName
            if mirrored:
                config = Config.getInstance()
                mirrorMap = config.getNameTemplate()['mirrorMap']
                component.setLocation(mirrorMap[componentData['location']])
                nameMapping[decoratedName] = componentData[
                    'name'] + component.getNameDecoration()
                component.pasteData(componentData, setLocation=False)
            else:
                component.pasteData(componentData, setLocation=True)

            graphPos = component.getGraphPos()
            component.setGraphPos(
                Vec2(graphPos.x + delta.x(), graphPos.y + delta.y()))

            node = KNode(self, component)
            self.addNode(node)
            self.selectNode(node, False)

            # save a dict of the nodes using the orignal names
            pastedComponents[nameMapping[decoratedName]] = component

        # Create Connections
        for connectionData in clipboardData['connections']:
            sourceComponentDecoratedName, outputName = connectionData[
                'source'].split('.')
            targetComponentDecoratedName, inputName = connectionData[
                'target'].split('.')

            sourceComponent = None

            # The connection is either between nodes that were pasted, or from pasted nodes
            # to unpasted nodes. We first check that the source component is in the pasted group
            # else use the node in the graph.
            if sourceComponentDecoratedName in nameMapping:
                sourceComponent = pastedComponents[
                    nameMapping[sourceComponentDecoratedName]]
            else:
                if not createConnectionsToExistingNodes:
                    continue

                # When we support copying/pasting between rigs, then we may not find the source
                # node in the target rig.
                if not self.hasNode(sourceComponentDecoratedName):
                    continue
                node = self.getNode(sourceComponentDecoratedName)
                sourceComponent = node.getComponent()

            targetComponentDecoratedName = nameMapping[
                targetComponentDecoratedName]
            targetComponent = pastedComponents[targetComponentDecoratedName]

            outputPort = sourceComponent.getOutputByName(outputName)
            inputPort = targetComponent.getInputByName(inputName)

            inputPort.setConnection(outputPort)
            self.connectPorts(srcNode=sourceComponent.getDecoratedName(),
                              outputName=outputPort.getName(),
                              tgtNode=targetComponent.getDecoratedName(),
                              inputName=inputPort.getName())
Exemple #27
0
 def minimumSizeHint(self):
     return QtCore.QSize(10, 25)
Exemple #28
0
class Node(QtWidgets.QGraphicsWidget):

    nameChanged = QtCore.Signal(str, str)

    __defaultColor = QtGui.QColor(154, 205, 50, 255)
    __defaultUnselectedColor = QtGui.QColor(25, 25, 25)
    __defaultSelectedColor = QtGui.QColor(255, 255, 255, 255)

    __defaultUnselectedPen = QtGui.QPen(__defaultUnselectedColor, 1.6)
    __defaultSelectedPen = QtGui.QPen(__defaultSelectedColor, 1.6)
    __defaultLinePen = QtGui.QPen(QtGui.QColor(25, 25, 25, 255), 1.25)

    def __init__(self, graph, name):
        super(Node, self).__init__()

        self.__name = name
        self.__graph = graph
        self.__color = self.__defaultColor
        self.__unselectedColor = self.__defaultUnselectedColor
        self.__selectedColor = self.__defaultSelectedColor

        self.__unselectedPen = QtGui.QPen(self.__defaultUnselectedPen)
        self.__selectedPen = QtGui.QPen(self.__defaultSelectedPen)
        self.__linePen = QtGui.QPen(self.__defaultLinePen)

        self.setMinimumWidth(60)
        self.setMinimumHeight(20)
        self.setSizePolicy(
            QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                  QtWidgets.QSizePolicy.Expanding))

        layout = QtWidgets.QGraphicsLinearLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        layout.setOrientation(QtCore.Qt.Vertical)
        self.setLayout(layout)

        self.__headerItem = NodeHeader(self.__name, self)
        layout.addItem(self.__headerItem)
        layout.setAlignment(self.__headerItem,
                            QtCore.Qt.AlignCenter | QtCore.Qt.AlignTop)

        self.__ports = []
        self.__inputPortsHolder = PortList(self)
        self.__ioPortsHolder = PortList(self)
        self.__outputPortsHolder = PortList(self)

        layout.addItem(self.__inputPortsHolder)
        layout.addItem(self.__ioPortsHolder)
        layout.addItem(self.__outputPortsHolder)

        self.__selected = False
        self.__dragging = False

    # =====
    # Name
    # =====
    def getName(self):
        return self.__name

    def setName(self, name):
        if name != self.__name:
            origName = self.__name
            self.__name = name
            self.__headerItem.setText(self.__name)

            # Emit an event, so that the graph can update itsself.
            self.nameChanged.emit(origName, name)

            # Update the node so that the size is computed.
            self.adjustSize()

    # =======
    # Colors
    # =======
    def getColor(self):
        return self.__color

    def setColor(self, color):
        self.__color = color
        self.update()

    def getUnselectedColor(self):
        return self.__unselectedColor

    def setUnselectedColor(self, color):
        self.__unselectedColor = color
        self.__unselectedPen.setColor(self.__unselectedColor)
        self.update()

    def getSelectedColor(self):
        return self.__selectedColor

    def setSelectedColor(self, color):
        self.__selectedColor = color
        self.__selectedPen.setColor(self.__selectedColor)
        self.update()

    # =============
    # Misc Methods
    # =============
    def getGraph(self):
        return self.__graph

    def getHeader(self):
        return self.__headerItem

    # ==========
    # Selection
    # ==========
    def isSelected(self):
        return self.__selected

    def setSelected(self, selected=True):
        self.__selected = selected
        self.setZValue(20.0)
        self.update()

    #########################
    ## Graph Pos

    def getGraphPos(self):
        transform = self.transform()
        size = self.size()
        return QtCore.QPointF(transform.dx() + (size.width() * 0.5),
                              transform.dy() + (size.height() * 0.5))

    def setGraphPos(self, graphPos):
        self.prepareConnectionGeometryChange()
        size = self.size()
        self.setTransform(
            QtGui.QTransform.fromTranslate(
                graphPos.x() - (size.width() * 0.5),
                graphPos.y() - (size.height() * 0.5)), False)

    def translate(self, x, y):
        self.prepareConnectionGeometryChange()
        currPos = self.pos()
        super(Node, self).setPos(currPos.x() + x, currPos.y() + y)

    # Prior to moving the node, we need to tell the connections to prepare for a geometry change.
    # This method must be called preior to moving a node.
    def prepareConnectionGeometryChange(self):
        for port in self.__ports:
            if port.inCircle():
                for connection in port.inCircle().getConnections():
                    connection.prepareGeometryChange()
            if port.outCircle():
                for connection in port.outCircle().getConnections():
                    connection.prepareGeometryChange()

    #########################
    ## Ports

    def addPort(self, port):
        if isinstance(port, InputPort):
            self.__inputPortsHolder.addPort(
                port, QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        elif isinstance(port, OutputPort):
            self.__outputPortsHolder.addPort(
                port, QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        else:
            self.__ioPortsHolder.addPort(
                port, QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
        self.__ports.append(port)

        self.adjustSize()
        return port

    def getPort(self, name):
        for port in self.__ports:
            if port.getName() == name:
                return port
        return None

    def getInputPort(self, name):
        for port in self.__ports:
            if port.getName() == name and isinstance(port,
                                                     (InputPort, IOPort)):
                return port
        return None

    def getOutputPort(self, name):
        for port in self.__ports:
            if port.getName() == name and isinstance(port,
                                                     (OutputPort, IOPort)):
                return port
        return None

    def paint(self, painter, option, widget):
        rect = self.windowFrameRect()
        painter.setBrush(self.__color)

        painter.setPen(QtGui.QPen(QtGui.QColor(0, 0, 0, 0), 0))

        roundingY = 10
        roundingX = rect.height() / rect.width() * roundingY

        painter.drawRoundRect(rect, roundingX, roundingY)

        # Title BG
        titleHeight = self.__headerItem.size().height() - 3

        painter.setBrush(self.__color.darker(125))
        roundingY = rect.width() * roundingX / titleHeight
        painter.drawRoundRect(0, 0, rect.width(), titleHeight, roundingX,
                              roundingY)
        painter.drawRect(0, titleHeight * 0.5 + 2, rect.width(),
                         titleHeight * 0.5)

        # painter.setPen(self.__linePen)
        # painter.drawLine(QtCore.QPoint(0, titleHeight), QtCore.QPoint(rect.width(), titleHeight))

        painter.setBrush(QtGui.QColor(0, 0, 0, 0))
        if self.__selected:
            painter.setPen(self.__selectedPen)
        else:
            painter.setPen(self.__unselectedPen)

        roundingY = 10
        roundingX = rect.height() / rect.width() * roundingY

        painter.drawRoundRect(rect, roundingX, roundingY)

    #########################
    ## Events

    def mousePressEvent(self, event):
        if event.button() is QtCore.Qt.MouseButton.LeftButton:

            modifiers = event.modifiers()
            if modifiers == QtCore.Qt.ControlModifier:
                if not self.isSelected():
                    self.__graph.selectNode(self, clearSelection=False)
                else:
                    self.__graph.deselectNode(self)

            elif modifiers == QtCore.Qt.ShiftModifier:
                if not self.isSelected():
                    self.__graph.selectNode(self, clearSelection=False)
            else:
                if not self.isSelected():
                    self.__graph.selectNode(self, clearSelection=True)

                    # Push all nodes back 1 level in z depth to bring selected
                    # node to front
                    for node in [x for x in self.__graph.getNodes().values()]:
                        if node == self:
                            continue

                        if node.zValue() != 0.0:
                            node.setZValue(node.zValue() - 1)

                self.__dragging = True
                self._mouseDownPoint = self.mapToScene(event.pos())
                self._mouseDelta = self._mouseDownPoint - self.getGraphPos()
                self._lastDragPoint = self._mouseDownPoint
                self._nodesMoved = False

        else:
            super(Node, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if self.__dragging:
            newPos = self.mapToScene(event.pos())

            graph = self.getGraph()
            if graph.getSnapToGrid() is True:
                gridSize = graph.getGridSize()

                newNodePos = newPos - self._mouseDelta

                snapPosX = math.floor(newNodePos.x() / gridSize) * gridSize
                snapPosY = math.floor(newNodePos.y() / gridSize) * gridSize
                snapPos = QtCore.QPointF(snapPosX, snapPosY)

                newPosOffset = snapPos - newNodePos

                newPos = newPos + newPosOffset

            delta = newPos - self._lastDragPoint
            self.__graph.moveSelectedNodes(delta)
            self._lastDragPoint = newPos
            self._nodesMoved = True
        else:
            super(Node, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        if self.__dragging:
            if self._nodesMoved:

                newPos = self.mapToScene(event.pos())

                delta = newPos - self._mouseDownPoint
                self.__graph.endMoveSelectedNodes(delta)

            self.setCursor(QtCore.Qt.ArrowCursor)
            self.__dragging = False
        else:
            super(Node, self).mouseReleaseEvent(event)

    #########################
    ## shut down

    def disconnectAllPorts(self):
        # gather all the connections into a list, and then remove them from the graph.
        # This is because we can't remove connections from ports while
        # iterating over the set.
        connections = []

        for port in self.__ports:
            if port.inCircle():
                for connection in port.inCircle().getConnections():
                    connections.append(connection)
            if port.outCircle():
                for connection in port.outCircle().getConnections():
                    connections.append(connection)

        for connection in connections:
            self.__graph.removeConnection(connection)
class KGraphViewWidget(GraphViewWidget):

    rigNameChanged = QtCore.Signal ()

    def __init__(self, parent=None):

        # constructors of base classes
        super(KGraphViewWidget, self).__init__(parent)

        self._builder = None
        self._guideBuilder = None
        self.guideRig = None

        graphView = KGraphView (parent = self)
        self.setGraphView (graphView)
        self.newRigPreset ()

    # ============
    # Rig Methods
    # ============
    def editRigName(self):
        dialog = QtWidgets.QInputDialog(self)
        dialog.setObjectName('RigNameDialog')
        text, ok = dialog.getText(self, 'Edit Rig Name', 'New Rig Name', text=self.guideRig.getName())

        if ok is True:
            self.setGuideRigName(text)

    def setGuideRigName(self, text):
        if text.endswith('_guide') is True:
            text = text.replace('_guide', '')

        self.guideRig.setName(text)
        self.rigNameChanged.emit()

    def newRigPreset(self):
        try:
            print "KGraphViewWidget.newRigPreset"
            self.guideRig = Rig()
            graphview=self.getGraphView()
            graphview.displayGraph(self.guideRig)
            self.setGuideRigName('MyRig')

            self.openedFile = None

            self.window().setWindowTitle('Beam Editor')

            print "newRigPreset,New Rig Created"

        except:
            print "newRigPreset,Error Creating New Rig"

    def buildGuideRig(self):
        self.window ().setCursor (QtCore.Qt.WaitCursor)

        if self.guideRig.getName().endswith('_guide') is False:
            self.guideRig.setName(self.guideRig.getName() + '_guide')

        if self._guideBuilder:
            self._guideBuilder.deleteBuildElements ()
        self._guideBuilder = plugins.getBuilder ()
        self._guideBuilder.build (self.guideRig)

        self.window ().setCursor (QtCore.Qt.ArrowCursor)

    def buildRig(self):
        print "buildRig"

    # ==============
    # Other Methods
    # ==============
    def addBackdrop(self, name='Backdrop'):
        graphView = self.getGraphView()

        initName = name
        suffix = 1
        collision = True
        while collision:

            collision = graphView.hasNode(name)
            if not collision:
                break

            result = re.split(r"(\d+)$", initName, 1)
            if len(result) > 1:
                initName = result[0]
                suffix = int(result[1])

            name = initName + str(suffix).zfill(2)
            suffix += 1

        backdropNode = KBackdrop(graphView, name)
        graphView.addNode(backdropNode)

        graphView.selectNode(backdropNode, clearSelection=True)

        return backdropNode
Exemple #30
0
 def getGraphPos(self):
     transform = self.transform()
     size = self.size()
     return QtCore.QPointF(transform.dx() + (size.width() * 0.5),
                           transform.dy() + (size.height() * 0.5))