Example #1
0
 def set_boxes(self, boxes):
     for box in boxes:
         box_item = QGraphicsRectItem()
         box_item.setPen(QPen(Qt.red, 4))
         box_item.setBrush(QBrush(Qt.NoBrush))
         box_item.setZValue(1)
         self.scene.addItem(box_item)
         box_item.hide()
         box_item.setRect(QRectF(box[0], box[1], box[2]-box[0], box[3]-box[1]))
         self.box_item_list.append(box_item)
Example #2
0
class Tile(QGraphicsRectItem):
    def __init__(self,
                 letter,
                 points,
                 coords,
                 scale,
                 on_position_change=None,
                 move_to_rack=None,
                 parent=None):
        QGraphicsRectItem.__init__(self, MARGIN, MARGIN,
                                   SQUARE_SIZE - 2 * MARGIN,
                                   SQUARE_SIZE - 2 * MARGIN, parent)
        if on_position_change:
            self.on_position_change = on_position_change
        if move_to_rack:
            self.move_to_rack = move_to_rack

        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.points = points
        self.letter = letter

        self.scale = scale
        self.setScale(self.scale)
        self.setZValue(3)

        self.setPen(QPen(YELLOW2, 0))
        self.setBrush(QBrush(YELLOW))

        tile_letter = letter.upper()
        self.letter_item = QGraphicsSimpleTextItem(tile_letter, self)

        self.font = QFont("Verdana", 20)
        if not points:
            self.font.setBold(True)
        font_metrics = QFontMetrics(self.font)
        height = font_metrics.height()
        width = font_metrics.width(tile_letter)

        self.letter_item.setX((SQUARE_SIZE - width) / 2 - MARGIN)
        self.letter_item.setY((SQUARE_SIZE - height) / 2 - MARGIN)
        self.letter_item.setFont(self.font)
        self.letter_item.setBrush(QBrush(SEA_GREEN))

        self.shadow = QGraphicsRectItem(MARGIN * 2, MARGIN * 2, SQUARE_SIZE,
                                        SQUARE_SIZE, self)
        self.shadow.setFlag(QGraphicsItem.ItemStacksBehindParent)
        self.shadow.setBrush(QBrush(TRANSPARENT_BLACK))
        self.shadow.setPen(QPen(TRANSPARENT, 0))
        self.shadow.hide()

        self.setPos(coords.x * SQUARE_SIZE * scale,
                    coords.y * SQUARE_SIZE * scale)
        self.coords = None
        self.update_coords()

        self.old_position = None
        self.old_coords = None

        self.is_placed = False

        if points:
            self.add_points()

    def __str__(self):
        return self.letter

    def add_points(self):
        points = QGraphicsSimpleTextItem(str(self.points), self)
        font = QFont("Verdana", 10)
        font_metrics = QFontMetrics(font)
        height = font_metrics.height()
        width = font_metrics.width(str(self.points))
        points.setFont(font)
        points.setBrush(QBrush(SEA_GREEN))
        points.setX(SQUARE_SIZE - MARGIN - width)
        points.setY(SQUARE_SIZE - MARGIN - height)

    def resize(self, scale):
        self.scale = scale
        self.setScale(scale)
        self.setPos(self.coords.x * SQUARE_SIZE * scale,
                    self.coords.y * SQUARE_SIZE * scale)

    def change_to_blank(self, new_letter):
        if self.letter == BLANK:
            self.letter = new_letter
            self.letter_item.setText(new_letter.upper())
            self.font.setBold(True)
            font_metrics = QFontMetrics(self.font)
            height = font_metrics.height()
            width = font_metrics.width(self.letter)
            self.letter_item.setFont(self.font)
            self.letter_item.setX((SQUARE_SIZE - width) / 2 - MARGIN)
            self.letter_item.setY((SQUARE_SIZE - height) / 2 - MARGIN)

    def change_back(self):
        self.letter = BLANK
        self.letter_item.setText(BLANK)

    def get_letter_and_points(self):
        return self.letter, self.points

    def mousePressEvent(self, event):
        if self.is_placed:
            return
        if event.button() == Qt.RightButton:
            return
        self.setScale(self.scale * 1.1)

        self.setZValue(10)
        self.old_position = self.pos()
        self.old_coords = self.coords

        self.setPos(self.x() - 2 * MARGIN, self.y() - 2 * MARGIN)
        self.shadow.show()
        QGraphicsRectItem.mousePressEvent(self, event)

    def mouseReleaseEvent(self, event):
        if self.is_placed:
            return
        if event.button() == Qt.RightButton:
            self.move_to_rack(self)
            return
        self.setScale(self.scale)

        current_position = self.pos()
        self.setX(
            round((self.x() + MARGIN * 2) / (SQUARE_SIZE * self.scale)) *
            SQUARE_SIZE * self.scale)
        self.setY(
            round((self.y() + MARGIN * 2) / (SQUARE_SIZE * self.scale)) *
            SQUARE_SIZE * self.scale)

        if current_position != self.pos():
            self.update_coords()
            self.on_position_change(self)

        self.setZValue(3)
        self.shadow.hide()
        QGraphicsRectItem.mouseReleaseEvent(self, event)

    def update_coords(self):
        x = round(self.x() / SQUARE_SIZE / self.scale)
        y = round(self.y() / SQUARE_SIZE / self.scale)
        self.coords = Coords(x, y)

    def move(self, position):
        self.setPos(position)
        self.update_coords()

    def move_to_coords(self, coords):
        position = QPoint(coords.x * SQUARE_SIZE * self.scale,
                          coords.y * SQUARE_SIZE * self.scale)
        self.move(position)

    def undo_move(self):
        self.setPos(self.old_position)
        self.update_coords()

    def swap_with_other(self, other):
        other.move(self.old_position)

    def remove_highlight(self):
        self.letter_item.setBrush(QBrush(SEA_GREEN))

    def place(self):
        self.letter_item.setBrush(QBrush(LIGHT_SEA_GREEN))
        self.setBrush(QBrush(YELLOW2))
        self.setPen(QPen(YELLOW2, 0))
        self.setFlag(QGraphicsItem.ItemIsMovable, False)
        self.is_placed = True
Example #3
0
class PreXoverLabel(QGraphicsSimpleTextItem):
    """Summary

    Attributes:
        is_fwd (TYPE): Description
    """
    _XO_FONT = styles.XOVER_LABEL_FONT
    _XO_BOLD = styles.XOVER_LABEL_FONT_BOLD
    _FM = QFontMetrics(_XO_FONT)

    def __init__(self, is_fwd, color, pre_xover_item):
        """Summary

        Args:
            is_fwd (TYPE): Description
            color (TYPE): Description
            pre_xover_item (TYPE): Description
        """
        super(QGraphicsSimpleTextItem, self).__init__(pre_xover_item)
        self.is_fwd = is_fwd
        self._color = color
        self._tbr = None
        self._outline = QGraphicsRectItem(self)
        self.setFont(self._XO_FONT)
        self.setBrush(getBrushObj('#666666'))

    # end def

    def resetItem(self, is_fwd, color):
        """Summary

        Args:
            is_fwd (TYPE): Description
            color (TYPE): Description

        Returns:
            TYPE: Description
        """
        self.is_fwd = is_fwd
        self._color = color

    # end def

    def setTextAndStyle(self, text, outline=False):
        """Summary

        Args:
            text (TYPE): Description
            outline (bool, optional): Description

        Returns:
            TYPE: Description
        """
        str_txt = str(text)
        self._tbr = tBR = self._FM.tightBoundingRect(str_txt)
        half_label_H = tBR.height() / 2.0
        half_label_W = tBR.width() / 2.0

        labelX = BASE_WIDTH / 2.0 - half_label_W
        if str_txt == '1':  # adjust for the number one
            labelX -= tBR.width()

        labelY = half_label_H if self.is_fwd else (BASE_WIDTH -
                                                   tBR.height()) / 2

        self.setPos(labelX, labelY)
        self.setText(str_txt)

        if outline:
            self.setFont(self._XO_BOLD)
            self.setBrush(getBrushObj('#ff0000'))
        else:
            self.setFont(self._XO_FONT)
            self.setBrush(getBrushObj('#666666'))

        if outline:
            r = QRectF(self._tbr).adjusted(-half_label_W, 0, half_label_W,
                                           half_label_H)
            self._outline.setRect(r)
            self._outline.setPen(getPenObj('#ff0000', 0.25))
            self._outline.setY(2 * half_label_H)
            self._outline.show()
        else:
            self._outline.hide()
Example #4
0
class ForcedXoverNode3(QGraphicsRectItem):
    """
    This is a QGraphicsRectItem to allow actions and also a
    QGraphicsSimpleTextItem to allow a label to be drawn

    Attributes:
        is_forward (TYPE): Description
    """
    def __init__(self, virtual_helix_item, xover_item, strand3p, idx):
        """Summary

        Args:
            virtual_helix_item (cadnano.gui.views.pathview.virtualhelixitem.VirtualHelixItem): from vhi
            xover_item (TYPE): Description
            strand3p (Strand): reference to the 3' strand
            idx (int): the base index within the virtual helix
        """
        super(ForcedXoverNode3, self).__init__(virtual_helix_item)
        self._vhi = virtual_helix_item
        self._xover_item = xover_item
        self._idx = idx

        self.is_forward = strand3p.strandSet().isForward()
        self._is_on_top = self.is_forward

        self._partner_virtual_helix = virtual_helix_item

        self._blank_thing = QGraphicsRectItem(_blankRect, self)
        self._blank_thing.setBrush(QBrush(Qt.white))
        self._path_thing = QGraphicsPathItem(self)
        self.configurePath()

        self._label = None
        self.setPen(_NO_PEN)
        self.setBrush(_NO_BRUSH)
        self.setRect(_rect)

        self.setZValue(styles.ZENDPOINTITEM + 1)
    # end def

    def updateForFloatFromVHI(self, virtual_helix_item, is_forward, idx_x, idx_y):
        """
        Args:
            virtual_helix_item (cadnano.gui.views.pathview.virtualhelixitem.VirtualHelixItem): Description
            is_forward (TYPE): Description
            idx_x (TYPE): Description
            idx_y (TYPE): Description
        """
        self._vhi = virtual_helix_item
        self.setParentItem(virtual_helix_item)
        self._idx = idx_x
        self._is_on_top = self.is_forward = True if is_forward else False
        self.updatePositionAndAppearance(is_from_strand=False)
    # end def

    def updateForFloatFromStrand(self, virtual_helix_item, strand3p, idx):
        """
        Args:
            virtual_helix_item (cadnano.gui.views.pathview.virtualhelixitem.VirtualHelixItem): Description
            strand3p (Strand): reference to the 3' strand
            idx (int): the base index within the virtual helix
        """
        self._vhi = virtual_helix_item
        self._strand = strand3p
        self.setParentItem(virtual_helix_item)
        self._idx = idx
        self._is_on_top = self.is_forward = strand3p.strandSet().isForward()
        self.updatePositionAndAppearance()
    # end def

    def configurePath(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._path_thing.setBrush(getBrushObj(_PENCIL_COLOR))
        path = PPR3 if self.is_forward else PPL3
        offset = -_BASE_WIDTH if self.is_forward else _BASE_WIDTH
        self._path_thing.setPath(path)
        self._path_thing.setPos(offset, 0)

        offset = -_BASE_WIDTH if self.is_forward else 0
        self._blank_thing.setPos(offset, 0)

        self._blank_thing.show()
        self._path_thing.show()
    # end def

    def refreshXover(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._xover_item.refreshXover()
    # end def

    def setPartnerVirtualHelix(self, virtual_helix_item):
        """Summary

        Args:
            virtual_helix_item (cadnano.gui.views.pathview.virtualhelixitem.VirtualHelixItem): Description

        Returns:
            TYPE: Description
        """
        self._partner_virtual_helix = virtual_helix_item
    # end def

    def idx(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._idx
    # end def

    def virtualHelixItem(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._vhi
    # end def

    def point(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._vhi.upperLeftCornerOfBaseType(self._idx, self.is_forward)
    # end def

    def floatPoint(self):
        """Summary

        Returns:
            TYPE: Description
        """
        pt = self.pos()
        return pt.x(), pt.y()
    # end def

    def isForward(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self.is_forward
    # end def

    def updatePositionAndAppearance(self, is_from_strand=True):
        """
        Sets position by asking the VirtualHelixItem
        Sets appearance by choosing among pre-defined painterpaths (from
        normalstrandgraphicsitem) depending on drawing direction.

        Args:
            is_from_strand (bool, optional): Description
        """
        self.setPos(*self.point())
        n5 = self._xover_item._node5
        if is_from_strand:
            from_strand, from_idx = (n5._strand, n5._idx) if n5 != self else (None, None)
            if self._strand.canInstallXoverAt(self._idx, from_strand, from_idx):
                self.configurePath()
                # We can only expose a 5' end. But on which side?
                is_left = True if self.is_forward else False
                self._updateLabel(is_left)
            else:
                self.hideItems()
        else:
            self.hideItems()
    # end def

    def remove(self):
        """Clean up this joint
        """
        scene = self.scene()
        scene.removeItem(self._label)
        self._label = None
        scene.removeItem(self._path_thing)
        self._path_thing = None
        scene.removeItem(self._blank_thing)
        self._blank_thing = None
        scene.removeItem(self)
    # end def

    def _updateLabel(self, is_left):
        """Called by updatePositionAndAppearance during init.
        Updates drawing and position of the label.

        Args:
            is_left (TYPE): Description
        """
        lbl = self._label
        if self._idx is not None:
            bw = _BASE_WIDTH
            num = self._partner_virtual_helix.idNum()
            tBR = _FM.tightBoundingRect(str(num))
            half_label_h = tBR.height()/2.0
            half_label_w = tBR.width()/2.0
            # determine x and y positions
            label_x = bw/2.0 - half_label_w
            if self._is_on_top:
                label_y = -0.25*half_label_h - 0.5 - 0.5*bw
            else:
                label_y = 2*half_label_h + 0.5 + 0.5*bw
            # adjust x for left vs right
            label_x_offset = 0.25*bw if is_left else -0.25*bw
            label_x += label_x_offset
            # adjust x for numeral 1
            if num == 1:
                label_x -= half_label_w/2.0
            # create text item
            if lbl is None:
                lbl = QGraphicsSimpleTextItem(str(num), self)
            lbl.setPos(label_x, label_y)
            lbl.setBrush(_ENAB_BRUSH)
            lbl.setFont(_TO_HELIX_NUM_FONT)
            self._label = lbl

            lbl.setText(str(self._partner_virtual_helix.idNum()))
            lbl.show()
        # end if
    # end def

    def hideItems(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if self._label:
            self._label.hide()
        if self._blank_thing:
            self._path_thing.hide()
        if self._blank_thing:
            self._blank_thing.hide()
Example #5
0
class ForcedXoverNode3(QGraphicsRectItem):
    """
    This is a QGraphicsRectItem to allow actions and also a
    QGraphicsSimpleTextItem to allow a label to be drawn

    Attributes:
        is_forward (TYPE): Description
    """

    def __init__(self, virtual_helix_item, xover_item, strand3p, idx):
        """Summary

        Args:
            virtual_helix_item (cadnano.views.pathview.virtualhelixitem.VirtualHelixItem): from vhi
            xover_item (TYPE): Description
            strand3p (Strand): reference to the 3' strand
            idx (int): the base index within the virtual helix
        """
        super(ForcedXoverNode3, self).__init__(virtual_helix_item)
        self._vhi = virtual_helix_item
        self._xover_item = xover_item
        self._idx = idx

        self.is_forward = strand3p.strandSet().isForward()
        self._is_on_top = self.is_forward

        self._partner_virtual_helix = virtual_helix_item

        self._blank_thing = QGraphicsRectItem(_blankRect, self)
        self._blank_thing.setBrush(QBrush(Qt.white))
        self._path_thing = QGraphicsPathItem(self)
        self.configurePath()

        self._label = None
        self.setPen(_NO_PEN)
        self.setBrush(_NO_BRUSH)
        self.setRect(_rect)

        self.setZValue(styles.ZENDPOINTITEM + 1)
    # end def

    def updateForFloatFromVHI(self, virtual_helix_item, is_forward, idx_x, idx_y):
        """
        Args:
            virtual_helix_item (cadnano.views.pathview.virtualhelixitem.VirtualHelixItem): Description
            is_forward (TYPE): Description
            idx_x (TYPE): Description
            idx_y (TYPE): Description
        """
        self._vhi = virtual_helix_item
        self.setParentItem(virtual_helix_item)
        self._idx = idx_x
        self._is_on_top = self.is_forward = True if is_forward else False
        self.updatePositionAndAppearance(is_from_strand=False)
    # end def

    def updateForFloatFromStrand(self, virtual_helix_item, strand3p, idx):
        """
        Args:
            virtual_helix_item (cadnano.views.pathview.virtualhelixitem.VirtualHelixItem): Description
            strand3p (Strand): reference to the 3' strand
            idx (int): the base index within the virtual helix
        """
        self._vhi = virtual_helix_item
        self._strand = strand3p
        self.setParentItem(virtual_helix_item)
        self._idx = idx
        self._is_on_top = self.is_forward = strand3p.strandSet().isForward()
        self.updatePositionAndAppearance()
    # end def

    def configurePath(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._path_thing.setBrush(getBrushObj(_PENCIL_COLOR))
        path = PPR3 if self.is_forward else PPL3
        offset = -_BASE_WIDTH if self.is_forward else _BASE_WIDTH
        self._path_thing.setPath(path)
        self._path_thing.setPos(offset, 0)

        offset = -_BASE_WIDTH if self.is_forward else 0
        self._blank_thing.setPos(offset, 0)

        self._blank_thing.show()
        self._path_thing.show()
    # end def

    def refreshXover(self):
        """Summary

        Returns:
            TYPE: Description
        """
        self._xover_item.refreshXover()
    # end def

    def setPartnerVirtualHelix(self, virtual_helix_item):
        """Summary

        Args:
            virtual_helix_item (cadnano.views.pathview.virtualhelixitem.VirtualHelixItem): Description

        Returns:
            TYPE: Description
        """
        self._partner_virtual_helix = virtual_helix_item
    # end def

    def idx(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._idx
    # end def

    def virtualHelixItem(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._vhi
    # end def

    def point(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self._vhi.upperLeftCornerOfBaseType(self._idx, self.is_forward)
    # end def

    def floatPoint(self):
        """Summary

        Returns:
            TYPE: Description
        """
        pt = self.pos()
        return pt.x(), pt.y()
    # end def

    def isForward(self):
        """Summary

        Returns:
            TYPE: Description
        """
        return self.is_forward
    # end def

    def updatePositionAndAppearance(self, is_from_strand=True):
        """
        Sets position by asking the VirtualHelixItem
        Sets appearance by choosing among pre-defined painterpaths (from
        normalstrandgraphicsitem) depending on drawing direction.

        Args:
            is_from_strand (bool, optional): Description
        """
        self.setPos(*self.point())
        n5 = self._xover_item._node5
        if is_from_strand:
            from_strand, from_idx = (n5._strand, n5._idx) if n5 != self else (None, None)
            if self._strand.canInstallXoverAt(self._idx, from_strand, from_idx):
                self.configurePath()
                # We can only expose a 5' end. But on which side?
                is_left = True if self.is_forward else False
                self._updateLabel(is_left)
            else:
                self.hideItems()
        else:
            self.hideItems()
    # end def

    def remove(self):
        """Clean up this joint
        """
        scene = self.scene()
        scene.removeItem(self._label)
        self._label = None
        scene.removeItem(self._path_thing)
        self._path_thing = None
        scene.removeItem(self._blank_thing)
        self._blank_thing = None
        scene.removeItem(self)
    # end def

    def _updateLabel(self, is_left):
        """Called by updatePositionAndAppearance during init.
        Updates drawing and position of the label.

        Args:
            is_left (TYPE): Description
        """
        lbl = self._label
        if self._idx is not None:
            bw = _BASE_WIDTH
            num = self._partner_virtual_helix.idNum()
            tBR = _FM.tightBoundingRect(str(num))
            half_label_h = tBR.height()/2.0
            half_label_w = tBR.width()/2.0
            # determine x and y positions
            label_x = bw/2.0 - half_label_w
            if self._is_on_top:
                label_y = -0.25*half_label_h - 0.5 - 0.5*bw
            else:
                label_y = 2*half_label_h + 0.5 + 0.5*bw
            # adjust x for left vs right
            label_x_offset = 0.25*bw if is_left else -0.25*bw
            label_x += label_x_offset
            # adjust x for numeral 1
            if num == 1:
                label_x -= half_label_w/2.0
            # create text item
            if lbl is None:
                lbl = QGraphicsSimpleTextItem(str(num), self)
            lbl.setPos(label_x, label_y)
            lbl.setBrush(_ENAB_BRUSH)
            lbl.setFont(_TO_HELIX_NUM_FONT)
            self._label = lbl

            lbl.setText(str(self._partner_virtual_helix.idNum()))
            lbl.show()
        # end if
    # end def

    def hideItems(self):
        """Summary

        Returns:
            TYPE: Description
        """
        if self._label:
            self._label.hide()
        if self._blank_thing:
            self._path_thing.hide()
        if self._blank_thing:
            self._blank_thing.hide()
Example #6
0
class ForcedXoverNode3(QGraphicsRectItem):
    """
    This is a QGraphicsRectItem to allow actions and also a 
    QGraphicsSimpleTextItem to allow a label to be drawn
    """
    def __init__(self, virtual_helix_item, xover_item, strand3p, idx):
        super(ForcedXoverNode3, self).__init__(virtual_helix_item)
        self._vhi = virtual_helix_item
        self._xover_item = xover_item
        self._idx = idx
        self._is_on_top = virtual_helix_item.isStrandOnTop(strand3p)
        self._is_drawn_5_to_3 = strand3p.strandSet().isDrawn5to3()
        self._strand_type = strand3p.strandSet().strandType()

        self._partner_virtual_helix = virtual_helix_item

        self._blank_thing = QGraphicsRectItem(_blankRect, self)
        self._blank_thing.setBrush(QBrush(Qt.white))
        self._path_thing = QGraphicsPathItem(self)
        self.configurePath()

        self.setPen(_NO_PEN)
        self._label = None
        self.setPen(_NO_PEN)
        self.setBrush(_NO_BRUSH)
        self.setRect(_rect)

        self.setZValue(styles.ZENDPOINTITEM + 1)
    # end def

    def updateForFloatFromVHI(self, virtual_helix_item, strand_type, idx_x, idx_y):
        """

        """
        self._vhi = virtual_helix_item
        self.setParentItem(virtual_helix_item)
        self._strand_type = strand_type
        self._idx = idx_x
        self._is_on_top = self._is_drawn_5_to_3 = True if idx_y == 0 else False
        self.updatePositionAndAppearance(is_from_strand=False)
    # end def

    def updateForFloatFromStrand(self, virtual_helix_item, strand3p, idx):
        """

        """
        self._vhi = virtual_helix_item
        self._strand = strand3p
        self.setParentItem(virtual_helix_item)
        self._idx = idx
        self._is_on_top = virtual_helix_item.isStrandOnTop(strand3p)
        self._is_drawn_5_to_3 = strand3p.strandSet().isDrawn5to3()
        self._strand_type = strand3p.strandSet().strandType()
        self.updatePositionAndAppearance()
    # end def

    def strandType(self):
        return self._strand_type
    # end def

    def configurePath(self):
        self._path_thing.setBrush(QBrush(styles.RED_STROKE))
        path = PPR3 if self._is_drawn_5_to_3 else PPL3
        offset = -_BASE_WIDTH if self._is_drawn_5_to_3 else _BASE_WIDTH
        self._path_thing.setPath(path)
        self._path_thing.setPos(offset, 0)

        offset = -_BASE_WIDTH if self._is_drawn_5_to_3 else 0
        self._blank_thing.setPos(offset, 0)

        self._blank_thing.show()
        self._path_thing.show()
    # end def

    def refreshXover(self):
        self._xover_item.refreshXover()
    # end def

    def setPartnerVirtualHelix(self, virtual_helix_item):
        self._partner_virtual_helix = virtual_helix_item
    # end def

    def idx(self):
        return self._idx
    # end def

    def virtualHelixItem(self):
        return self._vhi
    # end def

    def point(self):
        return self._vhi.upperLeftCornerOfBaseType(self._idx, self._strand_type)
    # end def

    def floatPoint(self):
        pt = self.pos()
        return pt.x(), pt.y()
    # end def

    def isOnTop(self):
        return self._is_on_top
    # end def

    def isDrawn5to3(self):
        return self._is_drawn_5_to_3
    # end def

    def updatePositionAndAppearance(self, is_from_strand=True):
        """
        Sets position by asking the VirtualHelixItem
        Sets appearance by choosing among pre-defined painterpaths (from
        normalstrandgraphicsitem) depending on drawing direction.
        """
        self.setPos(*self.point())
        n5 = self._xover_item._node5
        if is_from_strand:
            from_strand, from_idx = (n5._strand, n5._idx) if n5 != self else (None, None)
            if self._strand.canInstallXoverAt(self._idx, from_strand, from_idx):
                self.configurePath()
                # We can only expose a 5' end. But on which side?
                is_left = True if self._is_drawn_5_to_3 else False
                self._updateLabel(is_left)
            else:
                self.hideItems()
        else:
            self.hideItems()
    # end def

    def updateConnectivity(self):
        is_left = True if self._is_drawn_5_to_3 else False
        self._updateLabel(is_left)
    # end def

    def remove(self):
        """
        Clean up this joint
        """
        scene = self.scene()
        scene.removeItem(self._label)
        self._label = None
        scene.removeItem(self._path_thing)
        self._path_thing = None
        scene.removeItem(self._blank_thing)
        self._blank_thing = None
        scene.removeItem(self)
    # end def

    def _updateLabel(self, is_left):
        """
        Called by updatePositionAndAppearance during init, or later by
        updateConnectivity. Updates drawing and position of the label.
        """
        lbl = self._label
        if self._idx != None:
            bw = _BASE_WIDTH
            num = self._partner_virtual_helix.number()
            tBR = _FM.tightBoundingRect(str(num))
            half_label_h = tBR.height()/2.0
            half_label_w = tBR.width()/2.0
            # determine x and y positions
            label_x = bw/2.0 - half_label_w
            if self._is_on_top:
                label_y = -0.25*half_label_h - 0.5 - 0.5*bw
            else:
                label_y = 2*half_label_h + 0.5 + 0.5*bw
            # adjust x for left vs right
            label_x_offset = 0.25*bw if is_left else -0.25*bw
            label_x += label_x_offset
            # adjust x for numeral 1
            if num == 1: label_x -= half_label_w/2.0
            # create text item
            if lbl == None:
                lbl = QGraphicsSimpleTextItem(str(num), self)
            lbl.setPos(label_x, label_y)
            lbl.setBrush(_ENAB_BRUSH)
            lbl.setFont(_TO_HELIX_NUM_FONT)
            self._label = lbl

            lbl.setText( str(self._partner_virtual_helix.number()) )
            lbl.show()
        # end if
    # end def

    def hideItems(self):
        if self._label:
            self._label.hide()
        if self._blank_thing:
            self._path_thing.hide()
        if self._blank_thing:
            self._blank_thing.hide()
    def updateLine(self):
        if self.points is not None:
            diameter = 2*self.radius
            rect = QRectF(-self.radius, -self.radius, diameter, diameter)

            if self.itemPos is not None:
                # TODO: NaNの時のEllipseItemの挙動を考える
                point = self.points[self.itemPos]

                if not isinstance(self.item, self.itemType):
                    print("call")
                    scene = self.scene()
                    if scene is not None:
                        scene.removeItem(self.item)

                    self.item = self.itemType(self)
                    self.item.setZValue(10)
                    self.item.setBrush(self.color)
                    self.item.setRect(rect)
                    self.setItemIsMovable(self.isItemMovable)

                elif self.drawItemFlag:
                    self.item.show()

                self.item.setPos(*point)
                self.item.mouseMoveEvent = self.generateItemMouseMoveEvent(self.item, point)
                self.item.mousePressEvent = self.generateItemMousePressEvent(self.item, point)

                self.textItem.setPos(*point)
                prev_range = range(self.itemPos, -1, -self.markDelta)[1:]
                next_range = range(self.itemPos, len(self.points), self.markDelta)[1:]
                num_mark = len(prev_range) + len(next_range)

                rect_half = QRectF(-self.radius/2, -self.radius/2, diameter/2, diameter/2)
                while num_mark < len(self.markItemList) and len(self.markItemList)!=0:
                    markItem = self.markItemList.pop()
                    markTextItem = self.markTextItemList.pop()
                    scene = self.scene()
                    if scene is not None:
                        scene.removeItem(markItem)
                        scene.removeItem(markTextItem)

                current_path = os.path.dirname(os.path.realpath(__file__))
                while len(self.markItemList) < num_mark:
                    # TODO: 目盛りを矢印に.
                    # markItem = QGraphicsSvgItem(os.path.join(current_path, "svg", "small_arrow.svg"), self)
                    markItem = QGraphicsRectItem(self)
                    markItem.setBrush(Qt.black)
                    markItem.setRect(rect_half)
                    markItem.setZValue(9)

                    # markItem.setFlags(QGraphicsItem.ItemIgnoresParentOpacity)
                    # markItem.setOpacity(1)

                    # print(markItem.boundingRect())
                    # xlate = markItem.boundingRect().center()
                    # t = QTransform()
                    # # t.translate(xlate.x(), xlate.y())
                    # t.rotate(90)
                    # t.scale(0.03, 0.03)
                    # # t.translate(-xlate.x(), -xlate.y())
                    # markItem.setTransform(t)

                    self.markItemList.append(markItem)

                    markTextItem = GraphicsTextItemWithBackground(self)
                    markTextItem.setBackgroundColor(Qt.black)
                    markTextItem.setDefaultTextColor(Qt.white)
                    self.markTextItemList.append(markTextItem)

                for markItem, markTextItem, index in zip(self.markItemList, self.markTextItemList, chain(prev_range, next_range)):
                    markItem.setPos(*self.points[index])

                    markTextItem.setPos(*self.points[index])
                    markTextItem.setPlainText(str(int((index-self.itemPos)/self.markDelta)))

                    if self.drawMarkItemFlag:
                        markItem.show()
                        markTextItem.show()
                    else:
                        markItem.hide()
                        markTextItem.hide()


            else:
                self.item.hide()
                self.textItem.hide()

                for item, textItem in zip(self.markItemList, self.markTextItemList):
                    item.hide()
                    textItem.hide()

            self.update()
Example #8
0
class PreXoverLabel(QGraphicsSimpleTextItem):
    """
    Attributes:
        is_fwd (bool): Description
    """
    _XO_FONT = styles.XOVER_LABEL_FONT
    _XO_BOLD = styles.XOVER_LABEL_FONT_BOLD
    _FM = QFontMetrics(_XO_FONT)

    def __init__(self, is_fwd: bool, pre_xover_item: 'PreXoverItem'):
        """
        Args:
            is_fwd: Description
            pre_xover_item: Description
        """
        super(QGraphicsSimpleTextItem, self).__init__(pre_xover_item)
        self.is_fwd = is_fwd
        self._tbr = None
        self._outline = QGraphicsRectItem(self)
        self.setFont(self._XO_FONT)
        self.setBrush(getBrushObj('#666666'))
    # end def

    def resetItem(self, is_fwd: bool, color: str):
        """
        Args:
            is_fwd: Description
            color: Description
        """
        self.resetTransform()
        self.is_fwd = is_fwd
        self.color = color
    # end def

    def setTextAndStyle(self, text: str, outline: bool = False):
        """
        Args:
            text: Description
            outline: Default is ``False``
        """
        str_txt = str(text)
        self._tbr = tBR = self._FM.tightBoundingRect(str_txt)
        half_label_H = tBR.height() / 2.0
        half_label_W = tBR.width() / 2.0

        labelX = BASE_WIDTH/2.0 - half_label_W
        if str_txt == '1':  # adjust for the number one
            labelX -= tBR.width()

        labelY = half_label_H if self.is_fwd else (BASE_WIDTH - tBR.height())/2

        self.setPos(labelX, labelY)
        self.setText(str_txt)

        if outline:
            self.setFont(self._XO_BOLD)
            self.setBrush(getBrushObj('#ff0000'))
        else:
            self.setFont(self._XO_FONT)
            self.setBrush(getBrushObj('#666666'))

        if outline:
            r = QRectF(self._tbr).adjusted(-half_label_W, 0,
                                           half_label_W, half_label_H)
            self._outline.setRect(r)
            self._outline.setPen(getPenObj('#ff0000', 0.25))
            self._outline.setY(2*half_label_H)
            self._outline.show()
        else:
            self._outline.hide()
Example #9
0
class ForcedXoverNode3(QGraphicsRectItem):
    """
    This is a QGraphicsRectItem to allow actions and also a 
    QGraphicsSimpleTextItem to allow a label to be drawn
    """
    def __init__(self, virtual_helix_item, xover_item, strand3p, idx):
        super(ForcedXoverNode3, self).__init__(virtual_helix_item)
        self._vhi = virtual_helix_item
        self._xover_item = xover_item
        self._idx = idx
        self._is_on_top = virtual_helix_item.isStrandOnTop(strand3p)
        self._is_drawn_5_to_3 = strand3p.strandSet().isDrawn5to3()
        self._strand_type = strand3p.strandSet().strandType()

        self._partner_virtual_helix = virtual_helix_item

        self._blank_thing = QGraphicsRectItem(_blankRect, self)
        self._blank_thing.setBrush(QBrush(Qt.white))
        self._path_thing = QGraphicsPathItem(self)
        self.configurePath()

        self.setPen(_NO_PEN)
        self._label = None
        self.setPen(_NO_PEN)
        self.setBrush(_NO_BRUSH)
        self.setRect(_rect)

        self.setZValue(styles.ZENDPOINTITEM + 1)

    # end def

    def updateForFloatFromVHI(self, virtual_helix_item, strand_type, idx_x,
                              idx_y):
        """

        """
        self._vhi = virtual_helix_item
        self.setParentItem(virtual_helix_item)
        self._strand_type = strand_type
        self._idx = idx_x
        self._is_on_top = self._is_drawn_5_to_3 = True if idx_y == 0 else False
        self.updatePositionAndAppearance(is_from_strand=False)

    # end def

    def updateForFloatFromStrand(self, virtual_helix_item, strand3p, idx):
        """

        """
        self._vhi = virtual_helix_item
        self._strand = strand3p
        self.setParentItem(virtual_helix_item)
        self._idx = idx
        self._is_on_top = virtual_helix_item.isStrandOnTop(strand3p)
        self._is_drawn_5_to_3 = strand3p.strandSet().isDrawn5to3()
        self._strand_type = strand3p.strandSet().strandType()
        self.updatePositionAndAppearance()

    # end def

    def strandType(self):
        return self._strand_type

    # end def

    def configurePath(self):
        self._path_thing.setBrush(QBrush(styles.RED_STROKE))
        path = PPR3 if self._is_drawn_5_to_3 else PPL3
        offset = -_BASE_WIDTH if self._is_drawn_5_to_3 else _BASE_WIDTH
        self._path_thing.setPath(path)
        self._path_thing.setPos(offset, 0)

        offset = -_BASE_WIDTH if self._is_drawn_5_to_3 else 0
        self._blank_thing.setPos(offset, 0)

        self._blank_thing.show()
        self._path_thing.show()

    # end def

    def refreshXover(self):
        self._xover_item.refreshXover()

    # end def

    def setPartnerVirtualHelix(self, virtual_helix_item):
        self._partner_virtual_helix = virtual_helix_item

    # end def

    def idx(self):
        return self._idx

    # end def

    def virtualHelixItem(self):
        return self._vhi

    # end def

    def point(self):
        return self._vhi.upperLeftCornerOfBaseType(self._idx,
                                                   self._strand_type)

    # end def

    def floatPoint(self):
        pt = self.pos()
        return pt.x(), pt.y()

    # end def

    def isOnTop(self):
        return self._is_on_top

    # end def

    def isDrawn5to3(self):
        return self._is_drawn_5_to_3

    # end def

    def updatePositionAndAppearance(self, is_from_strand=True):
        """
        Sets position by asking the VirtualHelixItem
        Sets appearance by choosing among pre-defined painterpaths (from
        normalstrandgraphicsitem) depending on drawing direction.
        """
        self.setPos(*self.point())
        n5 = self._xover_item._node5
        if is_from_strand:
            from_strand, from_idx = (n5._strand,
                                     n5._idx) if n5 != self else (None, None)
            if self._strand.canInstallXoverAt(self._idx, from_strand,
                                              from_idx):
                self.configurePath()
                # We can only expose a 5' end. But on which side?
                is_left = True if self._is_drawn_5_to_3 else False
                self._updateLabel(is_left)
            else:
                self.hideItems()
        else:
            self.hideItems()

    # end def

    def updateConnectivity(self):
        is_left = True if self._is_drawn_5_to_3 else False
        self._updateLabel(is_left)

    # end def

    def remove(self):
        """
        Clean up this joint
        """
        scene = self.scene()
        scene.removeItem(self._label)
        self._label = None
        scene.removeItem(self._path_thing)
        self._path_thing = None
        scene.removeItem(self._blank_thing)
        self._blank_thing = None
        scene.removeItem(self)

    # end def

    def _updateLabel(self, is_left):
        """
        Called by updatePositionAndAppearance during init, or later by
        updateConnectivity. Updates drawing and position of the label.
        """
        lbl = self._label
        if self._idx != None:
            bw = _BASE_WIDTH
            num = self._partner_virtual_helix.number()
            tBR = _FM.tightBoundingRect(str(num))
            half_label_h = tBR.height() / 2.0
            half_label_w = tBR.width() / 2.0
            # determine x and y positions
            label_x = bw / 2.0 - half_label_w
            if self._is_on_top:
                label_y = -0.25 * half_label_h - 0.5 - 0.5 * bw
            else:
                label_y = 2 * half_label_h + 0.5 + 0.5 * bw
            # adjust x for left vs right
            label_x_offset = 0.25 * bw if is_left else -0.25 * bw
            label_x += label_x_offset
            # adjust x for numeral 1
            if num == 1: label_x -= half_label_w / 2.0
            # create text item
            if lbl == None:
                lbl = QGraphicsSimpleTextItem(str(num), self)
            lbl.setPos(label_x, label_y)
            lbl.setBrush(_ENAB_BRUSH)
            lbl.setFont(_TO_HELIX_NUM_FONT)
            self._label = lbl

            lbl.setText(str(self._partner_virtual_helix.number()))
            lbl.show()
        # end if

    # end def

    def hideItems(self):
        if self._label:
            self._label.hide()
        if self._blank_thing:
            self._path_thing.hide()
        if self._blank_thing:
            self._blank_thing.hide()
Example #10
0
class NodeItem(QGraphicsItem):
    def __init__ (self, nodeobj, parent=None, view=None, state=1):
        super().__init__()
        self.edge = None
        self.linkIDs = None
        self.children = None
        self.childpos = None
        self.nodeobj = nodeobj
        self.style = FlGlob.mainwindow.style
        self.view = weakref.proxy(view)
        self.refID = parent.realid() if parent is not None else None
        self.state = state
        self.setrank(parent)
        self.setCursor(Qt.ArrowCursor)
        self.yoffset = 0
        self.graphicsetup()
        self.setstate(state)
    
    def id (self):
        return (self.refID, self.nodeobj.ID)
    
    def realid (self):
        return self.nodeobj.ID
    
    def childlist (self, generate=False):
        ID = self.nodeobj.ID
        itemtable = self.view.itemtable
        if self.state == 1 and ID in itemtable and not self.iscollapsed():
            if self.children and self.nodeobj.linkIDs == self.linkIDs and None not in [c() for c in self.children]:
                ret = self.children
            else:
                children = []
                for child in self.nodeobj.linkIDs:
                    if child in itemtable[ID]:
                        item = itemtable[ID][child]
                    else:
                        continue
                    children.append(weakref.ref(item))
                self.linkIDs = self.nodeobj.linkIDs.copy()
                self.children = children
                ret = children
        else:
            ret = []
        if generate:
            x = self.x()
            y = self.y()
            self.childpos = []
            for target in ret:
                t = target()
                self.childpos.append((t.x()+t.boundingRect().left()-self.style.activemargin-x, t.y()-y))
            if self.edge:
                if self.childpos != self.edge.childpos:
                    self.edge.prepareGeometryChange()
                    self.edge.sourceright = self.boundingRect().right()
                    self.edge.update(self.edge.boundingRect())
        return ret
    
    def setedge (self, edge):
        self.edge = edge
        edge.setX(self.x())
    
    def setactive (self, active):
        if active:
            self.activebox.show()
            self.mainbox.setBrush(QBrush(self.altcolor))
        else:
            self.activebox.hide()
            self.mainbox.setBrush(QBrush(self.maincolor))
    
    def setselected (self, selected):
        if selected:
            self.selectbox.show()
        else:
            self.selectbox.hide()
    
    def setstate (self, state):
        self.state = state
        if state == 1: # normal
            self.show()
            self.graphgroup.setOpacity(1)
            self.shadowbox.show()
        elif state == 0: # ghost
            self.show()
            self.graphgroup.setOpacity(0.7)
            self.shadowbox.hide()
        elif state == -1: # hidden
            self.hide()
    
    def setplaymode (self, playmode):
        if playmode:
            self.setOpacity(0.5)
        else:
            self.setOpacity(1)
    
    def setY (self, y):
        parent = self.view.itembyID(self.refID)
        y += self.getyoffset()
        if self.edge is not None:
            self.edge.setY(y)
        super().setY(y)
    
    def setrank (self, parent):
        if parent is None:
            return
        if self.issubnode():
            x = parent.x()
            self.setX(x)
        else:
            x = parent.x()+self.style.rankwidth
            self.setX(x)
            self.nudgechildren()
        if self.edge is not None:
            self.edge.setX(x)
    
    def nudgechildren (self):
        for child in self.childlist():
            child().setrank(self)
    
    def getyoffset (self):
        if self.nodeobj.nodebank == -1:
            return self.yoffset
        else:
            return self.view.itembyID(self.refID).getyoffset() + self.yoffset
    
    def hide (self):
        super().hide()
        if self.edge:
            self.edge.hide()
    
    def show (self):
        super().show()
        if self.edge:
            self.edge.show()
    
    def issubnode (self):
        return self.nodeobj.nodebank is not -1
    
    def isghost (self):
        return not self.state
    
    def realnode (self):
        return self.view.itembyID(self.nodeobj.ID)
    
    def isactive (self):
        return self.view.activenode is self
    
    def isselected (self):
        return self.view.selectednode is self
    
    def iscollapsed (self):
        return self.id() in self.view.collapsednodes
    
    def y_top (self):
        return self.y() - self.boundingRect().height()//2
    
    def y_bottom (self):
        return self.y() + self.boundingRect().height()//2
    
    def bulkshift (self, children, diff):
        self.setY(self.y() + diff)
        if children is None:
            children = [c() for c in self.childlist()]
        for child in children:
            child.bulkshift(None, diff)
    
    def treeposition (self, ranks=None):
        if ranks is None:
            ranks = dict()
        localranks = dict()
        children = [c() for c in self.childlist()]
        for child in children:
            localranks = child.treeposition(localranks)
        rank = self.x() // self.style.rankwidth
        if children:
            top = children[0].y_top()
            bottom = children[-1].y_bottom()
            self.setY((top+bottom)//2)
        localranks[rank] = [self.y_top, self.y_bottom]
        streeshift = None
        for r in localranks:
            if r in ranks:
                rankshift = ranks[r][1]() + self.style.rowgap - localranks[r][0]()
                if streeshift is None or rankshift > streeshift:
                    streeshift = rankshift
                ranks[r][1] = localranks[r][1]
            else:
                ranks[r] = localranks[r]
        if streeshift:
            self.bulkshift(children, streeshift)
        return ranks
    
    def siblings (self):
        if self.refID is None:
            return None
        parent = self.view.nodecontainer.nodes[self.refID]
        if self.issubnode():
            return parent.subnodes
        else:
            return parent.linkIDs
    
    def siblingabove (self):
        sibs = self.siblings()
        if sibs is None or self.nodeobj.ID not in sibs:
            return None
        myindex = sibs.index(self.nodeobj.ID)
        if myindex:
            sibID = (self.refID, sibs[myindex-1])
            return self.view.itembyfullID(sibID)
        else:
            return None
    
    def siblingbelow (self):
        sibs = self.siblings()
        if sibs is None or self.nodeobj.ID not in sibs:
            return None
        myindex = sibs.index(self.nodeobj.ID)
        if len(sibs) > myindex+1:
            sibID = (self.refID, sibs[myindex+1])
            return self.view.itembyfullID(sibID)
        else:
            return None
    
    def subtreesize (self, depth=-1):
        """Find vertical extents of a subtree.
        
        Returns min/max y coordinates up to given depth (negative depth means
        whole subtree)."""

        # calculate child positions for EgdeItem only once when calculating scenerect
        if depth<0:
            generate = True
        else:
            generate = False
        
        children = [c() for c in self.childlist(generate=generate)]
        maxdepth = abs(depth)
        if children and depth:
            nextdepth = depth-1
            ymin = self.y_top()
            ymax = self.y_bottom()
            for child in children:
                top, bottom, depth = child.subtreesize(nextdepth)
                ymin = min(ymin, top)
                ymax = max(ymax, bottom)
                maxdepth = max(maxdepth, depth)
        else:
            ymin = self.y_top()
            ymax = self.y_bottom()
        return ymin, ymax, maxdepth
        
    def boundingRect (self):
        return self.rect
    
    def paint (self, painter, style, widget):
        pass
    
    def pixmap (self, path):
        return QPixmap(path).scaledToWidth(self.style.boldheight, Qt.SmoothTransformation)
    
    def graphicsetup (self):
        lightbrush = QBrush(FlPalette.light)
        mainbrush = QBrush(self.maincolor)
        altbrush = QBrush(self.altcolor)
        nopen = QPen(0)
        viewport = self.view.viewport()
        
        self.graphgroup = QGraphicsItemGroup(self)
        self.fggroup = QGraphicsItemGroup(self)
        
        self.shadowbox = QGraphicsRectItem(self)
        self.shadowbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
        self.shadowbox.setBrush(FlPalette.dark)
        self.shadowbox.setPen(nopen)
        self.shadowbox.setPos(*(self.style.shadowoffset,)*2)
        self.graphgroup.addToGroup(self.shadowbox)
        
        self.activebox = QGraphicsRectItem(self)
        self.activebox.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
        activepen = QPen(self.maincolor, self.style.selectmargin, join=Qt.MiterJoin)
        self.activebox.setPen(activepen)
        self.activebox.hide()
        self.graphgroup.addToGroup(self.activebox)
        
        self.selectbox = QGraphicsRectItem(self)
        self.selectbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
        selectpen = QPen(FlPalette.light, self.style.selectmargin, join=Qt.MiterJoin)
        self.selectbox.setPen(selectpen)
        self.selectbox.hide()
        self.graphgroup.addToGroup(self.selectbox)
        
        self.mainbox = QGraphicsRectItem(self)
        self.mainbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
        self.mainbox.setBrush(mainbrush)
        self.mainbox.setPen(nopen)
        self.graphgroup.addToGroup(self.mainbox)
        
        self.nodelabel = QGraphicsSimpleTextItemCond(self, viewport)
        self.nodelabel.setBrush(lightbrush)
        self.nodelabel.setFont(self.style.boldfont)
        self.nodelabel.setText(self.label % self.realid())
        self.nodelabel.setPos(self.style.itemmargin, self.style.itemmargin)
        self.fggroup.addToGroup(self.nodelabel)
        
        self.icon = self.pixmap("images/blank.png")
        self.iwidth = self.icon.width()
        self.iconx = self.style.nodetextwidth
        
        self.condicon = QGraphicsPixmapItemCond(self.icon, self, viewport)
        self.condicon.setPos(self.iconx-self.iwidth, self.style.itemmargin)
        self.iconx = self.condicon.x()
        self.fggroup.addToGroup(self.condicon)
        
        self.randicon = QGraphicsPixmapItemCond(self.icon, self, viewport)
        self.randicon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin)
        self.iconx = self.randicon.x()
        self.fggroup.addToGroup(self.randicon)
        
        self.exiticon = QGraphicsPixmapItemCond(self.icon, self, viewport)
        self.exiticon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin)
        self.iconx = self.exiticon.x()
        self.fggroup.addToGroup(self.exiticon)
        
        self.entericon = QGraphicsPixmapItemCond(self.icon, self, viewport)
        self.entericon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin)
        self.iconx = self.entericon.x()
        self.fggroup.addToGroup(self.entericon)
        
        self.persisticon = QGraphicsPixmapItemCond(self.icon, self, viewport)
        self.persisticon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin)
        self.iconx = self.persisticon.x()
        self.fggroup.addToGroup(self.persisticon)
        
        self.comment = QGraphicsTextItemCond(self, viewport)
        self.comment.setTextWidth(self.style.nodetextwidth)
        self.comment.setDefaultTextColor(FlPalette.light)
        self.comment.setPos(0, self.nodelabel.y()+self.nodelabel.boundingRect().height()+self.style.itemmargin)
        self.fggroup.addToGroup(self.comment)
        
        self.graphgroup.addToGroup(self.fggroup)
        
        self.view.nodedocs[self.realid()]["comment"].contentsChanged.connect(self.updatecomment)
        self.updatecondition()
        self.updateenterscripts()
        self.updateexitscripts()
        self.updaterandweight()
        self.updatepersistence()
        
        # Never call updatelayout() from here (or any inheritable reimplementation)!
    
    def collapse (self, collapse):
        for item in self.fggroup.childItems():
            if item is not self.nodelabel:
                if collapse:
                    item.hide()
                else:
                    item.show()
        self.updatelayout()
    
    def updatecondition (self):
        icons = {True: "key", False: "blank"}
        pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.hascond()])
        self.condicon.setPixmap(pixmap)
        if self.nodeobj.hascond():
            self.condicon.setToolTip("Condition")
        else:
            self.condicon.setToolTip("")
    
    def updateenterscripts (self):
        icons = {True: "script-enter", False: "blank"}
        pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.hasenterscripts()])
        self.entericon.setPixmap(pixmap)
        if self.nodeobj.hasenterscripts():
            self.entericon.setToolTip("Enter Scripts")
        else:
            self.entericon.setToolTip("")
    
    def updateexitscripts (self):
        icons = {True: "script-exit", False: "blank"}
        pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.hasexitscripts()])
        self.exiticon.setPixmap(pixmap)
        if self.nodeobj.hasexitscripts():
            self.exiticon.setToolTip("Exit Scripts")
        else:
            self.exiticon.setToolTip("")
    
    def updaterandweight (self):
        icons = {True: "dice", False: "blank"}
        pixmap = self.pixmap("images/%s.png" % icons[bool(self.nodeobj.randweight)])
        self.randicon.setPixmap(pixmap)
        if self.nodeobj.randweight:
            self.randicon.setToolTip("Random Weight: %s" % self.nodeobj.randweight)
        else:
            self.randicon.setToolTip("")
    
    def updatepersistence (self):
        icons = {"Mark": "mark", "OncePerConv": "once", "OnceEver": "onceever", "": "blank"}
        pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.persistence])
        self.persisticon.setPixmap(pixmap)
        if self.nodeobj.persistence:
            self.persisticon.setToolTip("Persistence: %s" % self.nodeobj.persistence)
        else:
            self.persisticon.setToolTip("")
    
    def updatecomment (self):
        self.fggroup.removeFromGroup(self.comment)
        contents = self.view.nodedocs[self.realid()]["comment"].toPlainText()
        if not contents:
            self.comment.hide()
        else:
            self.comment.show()
            self.comment.setPlainText(contents)
            self.fggroup.addToGroup(self.comment)
        self.updatelayout()
    
    def updatelayout (self):
        if self.iscollapsed():
            rect = self.nodelabel.mapRectToParent(self.nodelabel.boundingRect())
        else:
            rect = self.fggroup.childrenBoundingRect()
        mainrect = rect.marginsAdded(self.style.nodemargins)
        self.mainbox.setRect(mainrect)
        self.shadowbox.setRect(mainrect)
        self.selectbox.setRect(mainrect.marginsAdded(self.style.selectmargins))
        activerect = mainrect.marginsAdded(self.style.activemargins)
        self.activebox.setRect(activerect)
        self.graphgroup.setPos(-activerect.width()//2-activerect.x(), -activerect.height()//2-activerect.y())
        self.prepareGeometryChange()
        self.rect = self.graphgroup.mapRectToParent(mainrect)
        self.view.updatelayout()
    
    def mouseDoubleClickEvent (self, event):
        super().mouseDoubleClickEvent(event)
        event.accept()
        if event.button() == Qt.LeftButton:
            self.view.setactivenode(self)
    
    def mousePressEvent (self, event):
        super().mousePressEvent(event)
        if event.button() & (Qt.LeftButton | Qt.RightButton) :
            self.view.setselectednode(self)
            event.accept()
    
    def __repr__ (self):
        return "<%s %s>" % (type(self).__name__, self.id())
Example #11
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)
Example #12
0
class CalendarDesklet(Desklet):

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

        self.model = CalendarModel()

        self.cursor_pos = None

        self.cursor = QGraphicsRectItem(self.root)
        self.header = QGraphicsSimpleTextItem(self.root)

        self.weekdays = []
        days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
        for day in days:
            self.weekdays.append(QGraphicsSimpleTextItem(day, self.root))

        self.header_line = QGraphicsLineItem(self.root)

        self.days = []
        for _ in range(0, 6 * 7):
            self.days.append(QGraphicsSimpleTextItem(self.root))

    def next_month(self):
        self.model.next_month()
        self.layout()

    def previous_month(self):
        self.model.previous_month()
        self.layout()

    def set_rect(self, rect):
        super().set_rect(rect)
        self.layout()

    def set_style(self, style):
        super().set_style(style)

        font = QFont(style.font)
        font.setPixelSize(48)
        self.header.setBrush(style.midcolor)
        self.header.setFont(font)

        font = QFont(style.font)
        font.setPixelSize(32)

        self.header_line.setPen(style.foreground_color)

        self.cursor.setBrush(style.midcolor)
        self.cursor.setPen(QPen(Qt.NoPen))

        for widget in self.weekdays:
            widget.setFont(font)
            widget.setBrush(style.foreground_color)

        for widget in self.days:
            widget.setFont(font)
            widget.setBrush(self.style.foreground_color)

        self.layout()

    def layout(self):
        cell_width = (self.rect.width()) / 7.0
        cell_height = (self.rect.height() - 64) / 7.0

        x = self.rect.left()
        y = self.rect.top()

        fm = QFontMetrics(self.header.font())
        rect = fm.boundingRect(self.header.text())
        self.header.setPos(x + self.rect.width() / 2 - rect.width() / 2,
                           y)

        y += fm.height()

        for row, day in enumerate(self.weekdays):
            fm = QFontMetrics(day.font())
            rect = fm.boundingRect(day.text())
            day.setPos(x + row * cell_width + cell_width / 2 - rect.width() / 2,
                       y)

        y += fm.height()
        self.header_line.setLine(x, y,
                                 x + self.rect.width() - 3, y)

        y += 8

        for n, widget in enumerate(self.days):
            col = n % 7
            row = n // 7

            rect = fm.boundingRect(widget.text())
            widget.setPos(x + col * cell_width + cell_width / 2 - rect.width() / 2,
                          y + row * cell_height + cell_height / 2 - fm.height() / 2)

            # if day.month != self.now.month:
            #    widget.setBrush(self.style.midcolor)
            # else:

        if self.cursor_pos is not None:
            self.cursor.setRect(x + self.cursor_pos[0] * cell_width,
                                y + self.cursor_pos[1] * cell_height,
                                cell_width,
                                cell_height)
            self.cursor.show()
        else:
            self.cursor.hide()

    def update(self, now):
        self.model.update(now)

        # update header
        self.header.setText(
            date(self.model.year, self.model.month, 1).strftime("%B %Y"))

        # calculate the date of the top/left calendar entry
        current_date = date(self.model.year, self.model.month, 1)
        current_date = current_date - timedelta(current_date.weekday())

        self.cursor_pos = None
        for n, widget in enumerate(self.days):
            col = n % 7
            row = n // 7

            if current_date == self.model.today:
                self.cursor_pos = (col, row)

            widget.setText("%d" % current_date.day)
            self.days[n] = widget
            current_date += timedelta(days=1)

        self.layout()