Пример #1
0
    def __activeControlMoved(self, pos):
        # The active control point has moved, update the control
        # rectangle
        control = self.__activeControl
        pos = control.pos()
        rect = QRectF(self.__rect)
        margins = self.__margins

        # TODO: keyboard modifiers and constraints.

        anchor = control.anchor()
        if anchor & ControlPoint.Top:
            rect.setTop(pos.y() + margins.top())
        elif anchor & ControlPoint.Bottom:
            rect.setBottom(pos.y() - margins.bottom())

        if anchor & ControlPoint.Left:
            rect.setLeft(pos.x() + margins.left())
        elif anchor & ControlPoint.Right:
            rect.setRight(pos.x() - margins.right())

        changed = self.__rect != rect

        self.blockSignals(True)
        self.setRect(rect)
        self.blockSignals(False)

        if changed:
            self.rectEdited.emit(rect.normalized())
Пример #2
0
 def boundingRect(self):
     extra = (SfLine.ARROW_WIDTH + SfLine.ARROW_HEAD_LENGTH)/2.0 + 5
     size = QSizeF(self.line().p2().x() - self.line().p1().x(), 
                   self.line().p2().y() - self.line().p1().y())
     rect = QRectF(self.line().p1(), size)
     rect = rect.normalized()
     rect.adjust(-extra, -extra, extra, extra)
     return rect
Пример #3
0
class RectangleSelectionAction(UserInteraction):
    """
    Select items in the scene using a Rectangle selection
    """
    def __init__(self, document, *args, **kwargs):
        UserInteraction.__init__(self, document, *args, **kwargs)
        # The initial selection at drag start
        self.initial_selection = None
        # Selection when last updated in a mouseMoveEvent
        self.last_selection = None
        # A selection rect (`QRectF`)
        self.selection_rect = None
        # Keyboard modifiers
        self.modifiers = 0

    def mousePressEvent(self, event):
        pos = event.scenePos()
        any_item = self.scene.item_at(pos)
        if not any_item and event.button() & Qt.LeftButton:
            self.modifiers = event.modifiers()
            self.selection_rect = QRectF(pos, QSizeF(0, 0))
            self.rect_item = QGraphicsRectItem(
                self.selection_rect.normalized()
            )

            self.rect_item.setPen(
                QPen(QBrush(QColor(51, 153, 255, 192)),
                     0.4, Qt.SolidLine, Qt.RoundCap)
            )

            self.rect_item.setBrush(
                QBrush(QColor(168, 202, 236, 192))
            )

            self.rect_item.setZValue(-100)

            # Clear the focus if necessary.
            if not self.scene.stickyFocus():
                self.scene.clearFocus()

            if not self.modifiers & Qt.ControlModifier:
                self.scene.clearSelection()

            event.accept()
            return True
        else:
            self.cancel(self.ErrorReason)
            return False

    def mouseMoveEvent(self, event):
        if not self.rect_item.scene():
            # Add the rect item to the scene when the mouse moves.
            self.scene.addItem(self.rect_item)
        self.update_selection(event)
        return True

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            if self.initial_selection is None:
                # A single click.
                self.scene.clearSelection()
            else:
                self.update_selection(event)
        self.end()
        return True

    def update_selection(self, event):
        """
        Update the selection rectangle from a QGraphicsSceneMouseEvent
        `event` instance.

        """
        if self.initial_selection is None:
            self.initial_selection = set(self.scene.selectedItems())
            self.last_selection = self.initial_selection

        pos = event.scenePos()
        self.selection_rect = QRectF(self.selection_rect.topLeft(), pos)

        # Make sure the rect_item does not cause the scene rect to grow.
        rect = self._bound_selection_rect(self.selection_rect.normalized())

        # Need that 0.5 constant otherwise the sceneRect will still
        # grow (anti-aliasing correction by QGraphicsScene?)
        pw = self.rect_item.pen().width() + 0.5

        self.rect_item.setRect(rect.adjusted(pw, pw, -pw, -pw))

        selected = self.scene.items(self.selection_rect.normalized(),
                                    Qt.IntersectsItemShape,
                                    Qt.AscendingOrder)

        selected = set([item for item in selected if \
                        item.flags() & Qt.ItemIsSelectable])

        if self.modifiers & Qt.ControlModifier:
            for item in selected | self.last_selection | \
                    self.initial_selection:
                item.setSelected(
                    (item in selected) ^ (item in self.initial_selection)
                )
        else:
            for item in selected.union(self.last_selection):
                item.setSelected(item in selected)

        self.last_selection = set(self.scene.selectedItems())

    def end(self):
        self.initial_selection = None
        self.last_selection = None
        self.modifiers = 0

        self.rect_item.hide()
        if self.rect_item.scene() is not None:
            self.scene.removeItem(self.rect_item)
        UserInteraction.end(self)

    def viewport_rect(self):
        """
        Return the bounding rect of the document's viewport on the scene.
        """
        view = self.document.view()
        vsize = view.viewport().size()
        viewportrect = QRect(0, 0, vsize.width(), vsize.height())
        return view.mapToScene(viewportrect).boundingRect()

    def _bound_selection_rect(self, rect):
        """
        Bound the selection `rect` to a sensible size.
        """
        srect = self.scene.sceneRect()
        vrect = self.viewport_rect()
        maxrect = srect.united(vrect)
        return rect.intersected(maxrect)
Пример #4
0
class RectangleSelectionAction(UserInteraction):
    """
    Select items in the scene using a Rectangle selection
    """
    def __init__(self, document, *args, **kwargs):
        UserInteraction.__init__(self, document, *args, **kwargs)
        # The initial selection at drag start
        self.initial_selection = None
        # Selection when last updated in a mouseMoveEvent
        self.last_selection = None
        # A selection rect (`QRectF`)
        self.selection_rect = None
        # Keyboard modifiers
        self.modifiers = 0

    def mousePressEvent(self, event):
        pos = event.scenePos()
        any_item = self.scene.item_at(pos)
        if not any_item and event.button() & Qt.LeftButton:
            self.modifiers = event.modifiers()
            self.selection_rect = QRectF(pos, QSizeF(0, 0))
            self.rect_item = QGraphicsRectItem(
                self.selection_rect.normalized())

            self.rect_item.setPen(
                QPen(QBrush(QColor(51, 153, 255, 192)), 0.4, Qt.SolidLine,
                     Qt.RoundCap))

            self.rect_item.setBrush(QBrush(QColor(168, 202, 236, 192)))

            self.rect_item.setZValue(-100)

            # Clear the focus if necessary.
            if not self.scene.stickyFocus():
                self.scene.clearFocus()

            if not self.modifiers & Qt.ControlModifier:
                self.scene.clearSelection()

            event.accept()
            return True
        else:
            self.cancel(self.ErrorReason)
            return False

    def mouseMoveEvent(self, event):
        if not self.rect_item.scene():
            # Add the rect item to the scene when the mouse moves.
            self.scene.addItem(self.rect_item)
        self.update_selection(event)
        return True

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            if self.initial_selection is None:
                # A single click.
                self.scene.clearSelection()
            else:
                self.update_selection(event)
        self.end()
        return True

    def update_selection(self, event):
        """
        Update the selection rectangle from a QGraphicsSceneMouseEvent
        `event` instance.

        """
        if self.initial_selection is None:
            self.initial_selection = set(self.scene.selectedItems())
            self.last_selection = self.initial_selection

        pos = event.scenePos()
        self.selection_rect = QRectF(self.selection_rect.topLeft(), pos)

        # Make sure the rect_item does not cause the scene rect to grow.
        rect = self._bound_selection_rect(self.selection_rect.normalized())

        # Need that 0.5 constant otherwise the sceneRect will still
        # grow (anti-aliasing correction by QGraphicsScene?)
        pw = self.rect_item.pen().width() + 0.5

        self.rect_item.setRect(rect.adjusted(pw, pw, -pw, -pw))

        selected = self.scene.items(self.selection_rect.normalized(),
                                    Qt.IntersectsItemShape, Qt.AscendingOrder)

        selected = set([item for item in selected if \
                        item.flags() & Qt.ItemIsSelectable])

        if self.modifiers & Qt.ControlModifier:
            for item in selected | self.last_selection | \
                    self.initial_selection:
                item.setSelected((item in selected)
                                 ^ (item in self.initial_selection))
        else:
            for item in selected.union(self.last_selection):
                item.setSelected(item in selected)

        self.last_selection = set(self.scene.selectedItems())

    def end(self):
        self.initial_selection = None
        self.last_selection = None
        self.modifiers = 0

        self.rect_item.hide()
        if self.rect_item.scene() is not None:
            self.scene.removeItem(self.rect_item)
        UserInteraction.end(self)

    def viewport_rect(self):
        """
        Return the bounding rect of the document's viewport on the scene.
        """
        view = self.document.view()
        vsize = view.viewport().size()
        viewportrect = QRect(0, 0, vsize.width(), vsize.height())
        return view.mapToScene(viewportrect).boundingRect()

    def _bound_selection_rect(self, rect):
        """
        Bound the selection `rect` to a sensible size.
        """
        srect = self.scene.sceneRect()
        vrect = self.viewport_rect()
        maxrect = srect.united(vrect)
        return rect.intersected(maxrect)
Пример #5
0
class EFrameLayout(QGraphicsPolygonItem):

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

        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setAcceptsHoverEvents(True)

        self.__name = QGraphicsTextItem()
        self.__name.setPlainText('Frame Layout')

        self.__handleWidth = 500
        self.__handleHeight = 20
        self.__separator = 5
        self.__boundExtra = 3 + self.pen().width()
        self.__handleRect = QRectF( 0.0 , 0.0 , self.__handleWidth, self.__handleHeight  )

        self.__controlsBound = 0.0
        self.__controls = []

        self.__isDefaultPen = False
        self.__isCollapsed = True

        self.__pens = { 0: EDraw.EColor.DefaultLeaveHoverPen, 1: EDraw.EColor.DefaultEnterHoverPen }
        self.setPen(self.__pens[self.__isDefaultPen])

    @property
    def Label(self): return self.__name.toPlainText()

    @Label.setter
    def Label(self, label): self.__name.setPlainText( str( label ) )

    @property
    def Width(self): return self.__handleWidth

    @Width.setter
    def Width(self, width):
        self.__handleWidth = width
        self.updateGeometry()

    def toggleContentVisibility(self):
        if not len(self.__controls): return

        if self.__controls[0].isVisible():
            [ control.hide() for control in self.__controls ]
            self.__isCollapsed = True
            return

        [ control.show() for control in self.__controls ]
        self.__isCollapsed = False

    def updateGeometry(self):

        self.__handleRect = QRectF( 0.0 , 0.0 , self.__handleWidth, self.__handleHeight  )

        if not len(self.__controls) or self.__isCollapsed:
            self.__controlsBound = 0.0
            return

        self.__controlsBound = 0.0
        self.__controlsBound = self.__separator
        self.__controlsBound += sum( [ control.boundingRect().height() + self.__separator for control in self.__controls ] )

        step = self.__handleHeight + self.__separator * 2

        for control in self.__controls:

            control.Name.setTextWidth( self.__controlNameWidth )
            control.Width = self.__handleRect.normalized().adjusted( 5.0, 0.0, -5.0, 0.0 ).width()

            control.setPos( 5.0 , step )
            step += control.boundingRect().height() + self.__separator

    def addControl(self, control):
        if not isinstance(control, EControlsGroup): raise AttributeError

        self.__controls.append(control)
        control.setParentItem(self)
        control.setFlag(QGraphicsItem.ItemIsMovable, False)

        self.__controlNameWidth = max([ control.Name.boundingRect().width() for control in self.__controls ]) + 5

        self.__isCollapsed = False
        self.updateGeometry()

    def clear(self):
        [ control.setParentItem(None) for control in self.__controls ]
        self.__controls = []

        self.updateGeometry()

    def mouseDoubleClickEvent(self, mouseEvent):
        QGraphicsPolygonItem.mouseDoubleClickEvent(self, mouseEvent)

        self.toggleContentVisibility()
        self.updateGeometry()

    def shape(self): return QGraphicsItem.shape(self)

    def boundingRect(self):
        return self.__handleRect.normalized().adjusted( 0.0, 0.0, 0.0, self.__controlsBound )

    def paint(self, painter, option, widget=None):

        if not self.__isCollapsed:
            painter.setPen( QPen( QColor( 0, 0, 0, 50 ), 2 , Qt.SolidLine ) )
            painter.setBrush( QColor( 0, 0, 0, 50 ) )
            painter.drawRect( self.boundingRect().adjusted( self.pen().width(), self.__handleHeight , -self.pen().width(), 0.0 ) )

        painter.setPen(self.pen())
        painter.setBrush( EDraw.EColor.LinearGradient( self.__handleRect, Qt.darkGray ) )
        #painter.drawPolygon( QPolygonF( self.__handleRect.normalized().adjusted(-self.__boundExtra, 0.0, self.__boundExtra, 0.0 ) ) )
        painter.drawPolygon( QPolygonF( self.__handleRect ) )

        painter.setPen(Qt.lightGray)
        r = QRectF( 0.0, 0.0, self.__name.boundingRect().width(), self.__handleRect.height() )
        painter.drawText( r, Qt.AlignCenter, self.__name.toPlainText() )
Пример #6
0
class ENode(QGraphicsObject):

    onMove = pyqtSignal()
    onPress = pyqtSignal()

    kGuiPropertyId = EObject()
    kGuiPropertyName = EObject()

    kGuiAttribute = EObject()
    kGuiAttributeId = EObject()
    kGuiAttributeType = EObject()
    kGuiAttributePlug = EObject()
    kGuiAttributeParent = EObject()
    kGuiAttributeParentName = EObject()
    kGuiAttributeLongName = EObject()
    kGuiAttributeShortName = EObject()

    def __init__(self, eNodeHandle):
        QGraphicsObject.__init__(self)

        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setAcceptsHoverEvents(True)

        self.__isDefaultPen = False

        self.__pen = None
        self.__pens = {0: EDraw.EColor.DefaultLeaveHoverPen, 1: EDraw.EColor.DefaultEnterHoverPen}
        self.setPen(self.__pens[self.__isDefaultPen])

        self.__font = EDraw.DefaultNodeFont
        self.__nodeHandle = eNodeHandle
        self.__nodeHandle.Message.connect(self.__messageFilter)

        self.__name = self.__nodeHandle.__class__.__name__

        self.__attrRect = QRectF(0, 0, 15, 15)

        self.__titleRect = QRectF(0, 0, 135, 20)
        self.__textSpace = QRectF(self.__attrRect.width() + self.pen().width(), 0.0,
                                  (self.__titleRect.width() - self.__attrRect.width() * 2 - self.pen().width() * 2) / 2,
                                  self.__attrRect.height())

        self.buildAttributes()

        self.__height = max([self.__in_attr_step, self.__out_attr_step])

    def __messageFilter(self, message):
        if message.matches(self.__nodeHandle.kMessageAttributeAdded):
            self.__buildAttribute(message.getData())

        if message.matches(self.__nodeHandle.kMessageAttributeRemoved):

            print message.getData()

            self.__attributes = {}
            self.__properties = {}
            self.buildAttributes()

    def __getAttrShortName(self, attributeName):
        fm = QFontMetrics(self.__font)

        shortName = ''

        if fm.width(attributeName) > self.__textSpace.width():

            for x in range(len(attributeName) + 1):
                if fm.width(shortName) > int(self.__textSpace.width()) - 10:
                    return shortName

                shortName = attributeName[:x] + '...'

        return attributeName

    def __getAttributePosition(self, opposite=False):

        attr_x_pos = 0

        if opposite:

            attr_x_pos = self.__titleRect.width() - self.__attrRect.width()
            rect = self.__attrRect.translated(QPointF(attr_x_pos, self.__out_attr_step))

            point = QPointF((rect.topRight() + rect.bottomRight()) / 2)
            point.setX(point.x() + self.pen().width() * 2)

            self.__out_attr_step += self.__attrRect.width() + self.pen().width()

            return [rect, point]

        rect = self.__attrRect.translated(QPointF(attr_x_pos, self.__in_attr_step))
        point = QPointF((rect.topLeft() + rect.bottomLeft()) / 2)
        point.setX(point.x() - self.pen().width() * 2)

        self.__in_attr_step += self.__attrRect.width() + self.pen().width()

        return [rect, point]

    def __buildAttribute(self, attribute, opposite=False):

        """
        if not attribute.Type.matches(EAttribute.kTypeGenericInput) and not attribute.Type.matches(EAttribute.kTypeGenericOutput):

            self.__properties[attribute.Id] = dict({self.kGuiPropertyId: attribute.Id,
                                                    self.kGuiPropertyName: attribute.Name})
            return
        """

        data = self.__getAttributePosition(opposite)

        self.__attributes[data[0]] = dict({self.kGuiAttributeId: attribute.Id,
                                           self.kGuiAttributeType: attribute.Type,
                                           self.kGuiAttributeParent: self,
                                           self.kGuiAttributePlug: data[1],
                                           self.kGuiAttributeLongName: attribute.Name,
                                           self.kGuiAttributeShortName: self.__getAttrShortName(attribute.Name)})

        self.__height = max([self.__in_attr_step, self.__out_attr_step])

        self.update()
        self.onMove.emit()

    def buildAttributes(self):

        self.__attributes = {}
        self.__properties = {}

        self.__out_attr_step = self.__titleRect.height() + self.pen().width()
        self.__in_attr_step = self.__titleRect.height() + self.pen().width()

        for eddAttr in self.__nodeHandle.lsInputAttributes():
            self.__buildAttribute(eddAttr)

        for eddAttr in self.__nodeHandle.lsOutputAttributes():
            self.__buildAttribute(eddAttr, True)

        self.update()

    def __toggleHighlight(self):
        if self.__isDefaultPen:
            self.__isDefaultPen = False
            self.setPen(self.__pens[self.__isDefaultPen])
            #self.setZValue(0.0)
            return

        self.__isDefaultPen = True
        self.setPen(self.__pens[self.__isDefaultPen])
        #self.setZValue(-2.0)

    def mute(self, uuid):
        pass

    @property
    def Id(self):
        return self.__nodeHandle.Id

    @property
    def Name(self):
        return self.__name

    @Name.setter
    def Name(self, newName):
        self.__name = newName

    def pen(self):
        return self.__pen

    def setPen(self, pen):
        if not isinstance(pen, QPen):
            raise AttributeError

        self.__pen = pen

    @property
    def Font(self):
        return self.__font

    @Font.setter
    def Font(self, QFont):
        self.__font = QFont

    @property
    def Handle(self):
        return self.__nodeHandle

    @property
    def Properties(self):
        return self.__properties

    def mapFromPoint(self, QPoint):

        for attrRect, attrValues in self.__attributes.iteritems():
            if attrRect.contains(self.mapFromScene(QPoint)):
                return attrValues[self.kGuiAttributeId], QPoint

        return self.__nodeHandle.Id, None

    def mapFromId(self, attrId):

        for attrValue in self.__attributes.itervalues():
            if attrValue[self.kGuiAttributeId] == attrId:
                return attrValue

        return None

    def hoverEnterEvent(self, mouseEvent):
        QGraphicsObject.hoverEnterEvent(self, mouseEvent)
        self.__toggleHighlight()

    def hoverMoveEvent(self, mouseEvent):
        QGraphicsObject.hoverMoveEvent(self, mouseEvent)

    def hoverLeaveEvent(self, mouseEvent):
        QGraphicsObject.hoverLeaveEvent(self, mouseEvent)
        self.__toggleHighlight()

    def mousePressEvent(self, mouseEvent):
        QGraphicsObject.mousePressEvent(self, mouseEvent)

        #if mouseEvent.button() == Qt.RightButton:
        #print self.mapFromPoint(mouseEvent.scenePos())
        self.onPress.emit()

    def mouseDoubleClickEvent(self, mouseEvent):
        QGraphicsObject.mouseDoubleClickEvent(self, mouseEvent)

        #self.__nodeHandle.compute()

    def mouseMoveEvent(self, mouseEvent):
        QGraphicsObject.mouseMoveEvent(self, mouseEvent)
        self.onMove.emit()

    def boundingRect(self):
        extra = self.pen().width()
        return self.__titleRect.normalized().adjusted(-extra, -extra, extra,
                                                      (self.__height - self.__titleRect.height()) + extra)

    def shape(self):
        return QGraphicsItem.shape(self)

    def paint(self, painter, option, widget=None):

        painter.setBrush(EDraw.EColor.DefaultNodeFillColor)

        painter.setPen(self.pen())
        painter.drawRect(self.boundingRect())

        painter.setPen(Qt.NoPen)

        painter.setBrush(EDraw.EColor.DefaultTitleColor)
        painter.drawRect(self.__titleRect)

        painter.setPen(EDraw.EColor.DefaultTitleTextColor)
        painter.drawText(self.__titleRect, Qt.AlignCenter, self.__name)

        painter.setPen(Qt.NoPen)
        painter.setBrush(EDraw.EColor.DefaultAttributeFillColor)

        for rect in self.__attributes.iterkeys():
            painter.drawRect(rect)

        painter.setBrush(Qt.darkGray)
        for rect in self.__attributes.iterkeys():
            painter.drawPolygon(EDraw.Circle(rect.height() / 3, 3).translated(rect.center()))

        painter.setPen(QPen(QColor(43, 43, 43), 1.0, Qt.SolidLine))
        painter.setBrush(Qt.NoBrush)

        for attrRect, attrValues in self.__attributes.iteritems():

            attrNameRect = self.__textSpace.translated(attrRect.topLeft())
            align = Qt.AlignLeft

            if attrRect.topLeft().x() > 0:
                attrNameRect = self.__textSpace.translated(
                    QPointF((self.__titleRect.width() / 2) - (attrRect.width() + self.pen().width()),
                            attrRect.topLeft().y()))

                align = Qt.AlignRight

            painter.drawText(attrNameRect, align,  attrValues[self.kGuiAttributeShortName])
Пример #7
0
class EFrameLayout(QGraphicsPolygonItem):
    def __init__(self, parent=None, scene=None):
        super(EFrameLayout, self).__init__(parent, scene)

        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setAcceptsHoverEvents(True)

        self.__name = QGraphicsTextItem()
        self.__name.setPlainText('Frame Layout')

        self.__handleWidth = 500
        self.__handleHeight = 20
        self.__separator = 5
        self.__boundExtra = 3 + self.pen().width()
        self.__handleRect = QRectF(0.0, 0.0, self.__handleWidth,
                                   self.__handleHeight)

        self.__controlsBound = 0.0
        self.__controls = []

        self.__isDefaultPen = False
        self.__isCollapsed = True

        self.__pens = {
            0: EDraw.EColor.DefaultLeaveHoverPen,
            1: EDraw.EColor.DefaultEnterHoverPen
        }
        self.setPen(self.__pens[self.__isDefaultPen])

    @property
    def Label(self):
        return self.__name.toPlainText()

    @Label.setter
    def Label(self, label):
        self.__name.setPlainText(str(label))

    @property
    def Width(self):
        return self.__handleWidth

    @Width.setter
    def Width(self, width):
        self.__handleWidth = width
        self.updateGeometry()

    def toggleContentVisibility(self):
        if not len(self.__controls): return

        if self.__controls[0].isVisible():
            [control.hide() for control in self.__controls]
            self.__isCollapsed = True
            return

        [control.show() for control in self.__controls]
        self.__isCollapsed = False

    def updateGeometry(self):

        self.__handleRect = QRectF(0.0, 0.0, self.__handleWidth,
                                   self.__handleHeight)

        if not len(self.__controls) or self.__isCollapsed:
            self.__controlsBound = 0.0
            return

        self.__controlsBound = 0.0
        self.__controlsBound = self.__separator
        self.__controlsBound += sum([
            control.boundingRect().height() + self.__separator
            for control in self.__controls
        ])

        step = self.__handleHeight + self.__separator * 2

        for control in self.__controls:

            control.Name.setTextWidth(self.__controlNameWidth)
            control.Width = self.__handleRect.normalized().adjusted(
                5.0, 0.0, -5.0, 0.0).width()

            control.setPos(5.0, step)
            step += control.boundingRect().height() + self.__separator

    def addControl(self, control):
        if not isinstance(control, EControlsGroup): raise AttributeError

        self.__controls.append(control)
        control.setParentItem(self)
        control.setFlag(QGraphicsItem.ItemIsMovable, False)

        self.__controlNameWidth = max([
            control.Name.boundingRect().width() for control in self.__controls
        ]) + 5

        self.__isCollapsed = False
        self.updateGeometry()

    def clear(self):
        [control.setParentItem(None) for control in self.__controls]
        self.__controls = []

        self.updateGeometry()

    def mouseDoubleClickEvent(self, mouseEvent):
        QGraphicsPolygonItem.mouseDoubleClickEvent(self, mouseEvent)

        self.toggleContentVisibility()
        self.updateGeometry()

    def shape(self):
        return QGraphicsItem.shape(self)

    def boundingRect(self):
        return self.__handleRect.normalized().adjusted(0.0, 0.0, 0.0,
                                                       self.__controlsBound)

    def paint(self, painter, option, widget=None):

        if not self.__isCollapsed:
            painter.setPen(QPen(QColor(0, 0, 0, 50), 2, Qt.SolidLine))
            painter.setBrush(QColor(0, 0, 0, 50))
            painter.drawRect(self.boundingRect().adjusted(
                self.pen().width(), self.__handleHeight, -self.pen().width(),
                0.0))

        painter.setPen(self.pen())
        painter.setBrush(
            EDraw.EColor.LinearGradient(self.__handleRect, Qt.darkGray))
        #painter.drawPolygon( QPolygonF( self.__handleRect.normalized().adjusted(-self.__boundExtra, 0.0, self.__boundExtra, 0.0 ) ) )
        painter.drawPolygon(QPolygonF(self.__handleRect))

        painter.setPen(Qt.lightGray)
        r = QRectF(0.0, 0.0,
                   self.__name.boundingRect().width(),
                   self.__handleRect.height())
        painter.drawText(r, Qt.AlignCenter, self.__name.toPlainText())
Пример #8
0
class ControlPointRect(QGraphicsObject):
    Free = 0
    KeepAspectRatio = 1
    KeepCenter = 2

    rectChanged = Signal(QRectF)
    rectEdited = Signal(QRectF)

    def __init__(self, parent=None, rect=None, constraints=0, **kwargs):
        QGraphicsObject.__init__(self, parent, **kwargs)
        self.setFlag(QGraphicsItem.ItemHasNoContents)
        self.setFlag(QGraphicsItem.ItemIsFocusable)

        self.__rect = rect if rect is not None else QRectF()
        self.__margins = QMargins()
        points = \
            [ControlPoint(self, ControlPoint.Left),
             ControlPoint(self, ControlPoint.Top),
             ControlPoint(self, ControlPoint.TopLeft),
             ControlPoint(self, ControlPoint.Right),
             ControlPoint(self, ControlPoint.TopRight),
             ControlPoint(self, ControlPoint.Bottom),
             ControlPoint(self, ControlPoint.BottomLeft),
             ControlPoint(self, ControlPoint.BottomRight)
             ]
        assert(points == sorted(points, key=lambda p: p.anchor()))

        self.__points = dict((p.anchor(), p) for p in points)

        if self.scene():
            self.__installFilter()

        for p in points:
            p.setFlag(QGraphicsItem.ItemIsFocusable)
            p.setFocusProxy(self)

        self.controlPoint(ControlPoint.Top).setConstraint(Qt.Vertical)
        self.controlPoint(ControlPoint.Bottom).setConstraint(Qt.Vertical)
        self.controlPoint(ControlPoint.Left).setConstraint(Qt.Horizontal)
        self.controlPoint(ControlPoint.Right).setConstraint(Qt.Horizontal)

        self.__constraints = constraints
        self.__activeControl = None

        self.__pointsLayout()

    def controlPoint(self, anchor):
        """
        Return the anchor point (:class:`ControlPoint`) at anchor position
        or `None` if an anchor point is not set.

        """
        return self.__points.get(anchor)

    def setRect(self, rect):
        """
        Set the control point rectangle (:class:`QRectF`)
        """
        if self.__rect != rect:
            self.__rect = QRectF(rect)
            self.__pointsLayout()
            self.prepareGeometryChange()
            self.rectChanged.emit(rect.normalized())

    def rect(self):
        """
        Return the control point rectangle.
        """
        # Return the rect normalized. During the control point move the
        # rect can change to an invalid size, but the layout must still
        # know to which point does an unnormalized rect side belong,
        # so __rect is left unnormalized.
        # NOTE: This means all signal emits (rectChanged/Edited) must
        #       also emit normalized rects
        return self.__rect.normalized()

    rect_ = Property(QRectF, fget=rect, fset=setRect, user=True)

    def setControlMargins(self, *margins):
        """Set the controls points on the margins around `rect`
        """
        if len(margins) > 1:
            margins = QMargins(*margins)
        else:
            margins = margins[0]
            if isinstance(margins, int):
                margins = QMargins(margins, margins, margins, margins)

        if self.__margins != margins:
            self.__margins = margins
            self.__pointsLayout()

    def controlMargins(self):
        return self.__margins

    def setConstraints(self, constraints):
        raise NotImplementedError

    def isControlActive(self):
        """Return the state of the control. True if the control is
        active (user is dragging one of the points) False otherwise.

        """
        return self.__activeControl is not None

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemSceneHasChanged and self.scene():
            self.__installFilter()

        return QGraphicsObject.itemChange(self, change, value)

    def sceneEventFilter(self, obj, event):
        try:
            obj = toGraphicsObjectIfPossible(obj)
            if isinstance(obj, ControlPoint):
                etype = event.type()
                if etype == QEvent.GraphicsSceneMousePress and \
                        event.button() == Qt.LeftButton:
                    self.__setActiveControl(obj)

                elif etype == QEvent.GraphicsSceneMouseRelease and \
                        event.button() == Qt.LeftButton:
                    self.__setActiveControl(None)

        except Exception:
            log.error("Error in 'ControlPointRect.sceneEventFilter'",
                      exc_info=True)

        return QGraphicsObject.sceneEventFilter(self, obj, event)

    def __installFilter(self):
        # Install filters on the control points.
        try:
            for p in self.__points.values():
                p.installSceneEventFilter(self)
        except Exception:
            log.error("Error in ControlPointRect.__installFilter",
                      exc_info=True)

    def __pointsLayout(self):
        """Layout the control points
        """
        rect = self.__rect
        margins = self.__margins
        rect = rect.adjusted(-margins.left(), -margins.top(),
                             margins.right(), margins.bottom())
        center = rect.center()
        cx, cy = center.x(), center.y()
        left, top, right, bottom = \
                rect.left(), rect.top(), rect.right(), rect.bottom()

        self.controlPoint(ControlPoint.Left).setPos(left, cy)
        self.controlPoint(ControlPoint.Right).setPos(right, cy)
        self.controlPoint(ControlPoint.Top).setPos(cx, top)
        self.controlPoint(ControlPoint.Bottom).setPos(cx, bottom)

        self.controlPoint(ControlPoint.TopLeft).setPos(left, top)
        self.controlPoint(ControlPoint.TopRight).setPos(right, top)
        self.controlPoint(ControlPoint.BottomLeft).setPos(left, bottom)
        self.controlPoint(ControlPoint.BottomRight).setPos(right, bottom)

    def __setActiveControl(self, control):
        if self.__activeControl != control:
            if self.__activeControl is not None:
                self.__activeControl.positionChanged[QPointF].disconnect(
                    self.__activeControlMoved
                )

            self.__activeControl = control

            if control is not None:
                control.positionChanged[QPointF].connect(
                    self.__activeControlMoved
                )

    def __activeControlMoved(self, pos):
        # The active control point has moved, update the control
        # rectangle
        control = self.__activeControl
        pos = control.pos()
        rect = QRectF(self.__rect)
        margins = self.__margins

        # TODO: keyboard modifiers and constraints.

        anchor = control.anchor()
        if anchor & ControlPoint.Top:
            rect.setTop(pos.y() + margins.top())
        elif anchor & ControlPoint.Bottom:
            rect.setBottom(pos.y() - margins.bottom())

        if anchor & ControlPoint.Left:
            rect.setLeft(pos.x() + margins.left())
        elif anchor & ControlPoint.Right:
            rect.setRight(pos.x() - margins.right())

        changed = self.__rect != rect

        self.blockSignals(True)
        self.setRect(rect)
        self.blockSignals(False)

        if changed:
            self.rectEdited.emit(rect.normalized())

    def boundingRect(self):
        return QRectF()
Пример #9
0
class ENode(QGraphicsObject):

    onMove = pyqtSignal()
    onPress = pyqtSignal()

    kGuiAttributeId = EObject()
    kGuiAttributeType = EObject()
    kGuiAttributePlug = EObject()
    kGuiAttributeParent = EObject()
    kGuiAttributeParentName = EObject()
    kGuiAttributeLongName = EObject()
    kGuiAttributeShortName = EObject()

    def __init__(self, eNodeHandle):
        QGraphicsObject.__init__(self)

        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setAcceptsHoverEvents(True)

        self.__isDefaultPen = False

        self.__pen = None
        self.__pens = {
            0: EDraw.EColor.DefaultLeaveHoverPen,
            1: EDraw.EColor.DefaultEnterHoverPen
        }
        self.setPen(self.__pens[self.__isDefaultPen])

        self.Name = eNodeHandle.Name

        self.__font = QFont('Helvetica', 8, False)
        self.__nodeHandle = eNodeHandle
        self.__nodeHandle.Message.connect(self.__messageFilter)

        self.__attrRect = QRectF(0, 0, 15, 15)

        self.__titleRect = QRectF(0, 0, 125, 20)
        self.__textSpace = QRectF(
            self.__attrRect.width() + self.pen().width(), 0.0,
            (self.__titleRect.width() - self.__attrRect.width() * 2 -
             self.pen().width() * 2) / 2, self.__attrRect.height())

        self.__attributes = {}

        self.__out_attr_step = self.__titleRect.height() + self.pen().width()
        self.__in_attr_step = self.__titleRect.height() + self.pen().width()

        self.__buildAttributes()

        self.__height = max([self.__in_attr_step, self.__out_attr_step])

    def __messageFilter(self, message):
        if message.match(self.__nodeHandle.kMessageAttributeAdded):
            self.__buildAttribute(message.getData())

    def __getAttrShortName(self, attributeName):
        fm = QFontMetrics(self.__font)

        shortName = ''

        if fm.width(attributeName) > self.__textSpace.width():

            for x in range(len(attributeName) + 1):
                if fm.width(shortName) > int(self.__textSpace.width()) - 10:
                    return shortName

                shortName = attributeName[:x] + '...'

        return attributeName

    def __getAttributePosition(self, attrType):

        attr_x_pos = 0

        if attrType.match(EAttribute.kTypeOutput):

            attr_x_pos = self.__titleRect.width() - self.__attrRect.width()
            rect = self.__attrRect.translated(
                QPointF(attr_x_pos, self.__out_attr_step))

            point = QPointF((rect.topRight() + rect.bottomRight()) / 2)
            point.setX(point.x() + self.pen().width() * 2)

            self.__out_attr_step += self.__attrRect.width() + self.pen().width(
            )

            return [rect, point]

        rect = self.__attrRect.translated(
            QPointF(attr_x_pos, self.__in_attr_step))
        point = QPointF((rect.topLeft() + rect.bottomLeft()) / 2)
        point.setX(point.x() - self.pen().width() * 2)

        self.__in_attr_step += self.__attrRect.width() + self.pen().width()

        return [rect, point]

    def __buildAttribute(self, attribute):
        data = self.__getAttributePosition(attribute.Type)

        self.__attributes[data[0]] = dict({
            self.kGuiAttributeId:
            attribute.Id,
            self.kGuiAttributeType:
            attribute.Type,
            self.kGuiAttributeParent:
            self,
            self.kGuiAttributeParentName:
            self.__nodeHandle.Name,
            self.kGuiAttributePlug:
            data[1],
            self.kGuiAttributeLongName:
            attribute.Name,
            self.kGuiAttributeShortName:
            self.__getAttrShortName(attribute.Name)
        })

        self.__height = max([self.__in_attr_step, self.__out_attr_step])

        self.update()
        self.onMove.emit()

    def __buildAttributes(self):

        for eddAttr in self.__nodeHandle.ls():
            self.__buildAttribute(eddAttr)

    def __toggleHighlight(self):
        if self.__isDefaultPen:
            self.__isDefaultPen = False
            self.setPen(self.__pens[self.__isDefaultPen])
            #self.setZValue(0.0)
            return

        self.__isDefaultPen = True
        self.setPen(self.__pens[self.__isDefaultPen])
        #self.setZValue(-2.0)

    @property
    def Id(self):
        return self.__nodeHandle.Id

    def pen(self):
        return self.__pen

    def setPen(self, pen):
        if not isinstance(pen, QPen):
            raise AttributeError

        self.__pen = pen

    @property
    def Handle(self):
        return self.__nodeHandle

    def mapFromPoint(self, QPoint):

        for attrRect, attrValues in self.__attributes.iteritems():
            if attrRect.contains(self.mapFromScene(QPoint)):
                return attrValues[self.kGuiAttributeId]

        return self.__nodeHandle.Id

    def mapFromId(self, attrId):

        for attrValue in self.__attributes.itervalues():
            if attrValue[self.kGuiAttributeId] == attrId:
                return attrValue

        return None

    def hoverEnterEvent(self, mouseEvent):
        QGraphicsObject.hoverEnterEvent(self, mouseEvent)
        self.__toggleHighlight()

    def hoverMoveEvent(self, mouseEvent):
        QGraphicsObject.hoverMoveEvent(self, mouseEvent)

    def hoverLeaveEvent(self, mouseEvent):
        QGraphicsObject.hoverLeaveEvent(self, mouseEvent)
        self.__toggleHighlight()

    def mousePressEvent(self, mouseEvent):
        QGraphicsObject.mousePressEvent(self, mouseEvent)

        #if mouseEvent.button() == Qt.RightButton:
        #print self.mapFromPoint(mouseEvent.scenePos())
        self.onPress.emit()

    def mouseDoubleClickEvent(self, mouseEvent):
        QGraphicsObject.mouseDoubleClickEvent(self, mouseEvent)

        #self.__nodeHandle.compute()

    def mouseMoveEvent(self, mouseEvent):
        QGraphicsObject.mouseMoveEvent(self, mouseEvent)
        self.onMove.emit()

    def boundingRect(self):
        extra = self.pen().width()
        return self.__titleRect.normalized().adjusted(
            -extra, -extra, extra,
            (self.__height - self.__titleRect.height()) + extra)

    def shape(self):
        return QGraphicsItem.shape(self)

    def paint(self, painter, option, widget=None):

        painter.setBrush(Qt.darkGray)

        painter.setPen(self.pen())
        painter.drawRect(self.boundingRect())

        painter.setPen(Qt.NoPen)

        painter.setBrush(QColor(43, 43, 43))
        painter.drawRect(self.__titleRect)

        painter.setPen(Qt.darkGray)
        painter.drawText(self.__titleRect, Qt.AlignCenter, self.Name)

        painter.setPen(Qt.NoPen)
        painter.setBrush(QColor(60, 63, 65))

        for rect in self.__attributes.iterkeys():
            painter.drawRect(rect)

        painter.setBrush(Qt.darkGray)
        for rect in self.__attributes.iterkeys():
            painter.drawPolygon(
                EDraw.Circle(rect.height() / 3, 3).translated(rect.center()))

        painter.setPen(QPen(QColor(43, 43, 43), 1.0, Qt.SolidLine))
        painter.setBrush(Qt.NoBrush)

        painter.setFont(self.__font)
        for attrRect, attrValues in self.__attributes.iteritems():

            attrNameRect = self.__textSpace.translated(attrRect.topLeft())
            align = Qt.AlignLeft

            if attrRect.topLeft().x() > 0:
                attrNameRect = self.__textSpace.translated(
                    QPointF((self.__titleRect.width() / 2) -
                            (attrRect.width() + self.pen().width()),
                            attrRect.topLeft().y()))

                align = Qt.AlignRight

            painter.drawText(attrNameRect, align,
                             attrValues[self.kGuiAttributeShortName])