Ejemplo n.º 1
0
 def _updateLabel(self, isLeft):
     """
     Called by updatePositionAndAppearance during init, or later by
     updateConnectivity. Updates drawing and position of the label.
     """
     lbl = self._label
     if self._idx != None:
         if lbl == 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
             labelX = bw / 2.0 - half_label_w
             if self._is_on_top:
                 labelY = -0.25 * half_label_h - 0.5 - 0.5 * bw
             else:
                 labelY = 2 * half_label_h + 0.5 + 0.5 * bw
             # adjust x for left vs right
             labelXoffset = 0.25 * bw if isLeft else -0.25 * bw
             labelX += labelXoffset
             # adjust x for numeral 1
             if num == 1:
                 labelX -= half_label_w / 2.0
             # create text item
             lbl = QGraphicsSimpleTextItem(str(num), self)
             lbl.setPos(labelX, labelY)
             lbl.setBrush(_ENAB_BRUSH)
             lbl.setFont(_toHelixNumFont)
             self._label = lbl
         # end if
         lbl.setText(str(self._partner_virtual_helix.number()))
Ejemplo n.º 2
0
    def update_items(self):
        self.item = QGraphicsRectItem(0, 0, self.width,
                                      self.row_h * self.coeff_h)
        seq_width = 0
        nopen = QPen(Qt.NoPen)
        self.item.setPen(nopen)
        font = QFont(self.ftype, self.fsize)
        if self.fstyle == "italic":
            font.setStyle(QFont.StyleItalic)
        elif self.fstyle == "oblique":
            font.setStyle(QFont.StyleOblique)
        rect_cls = QGraphicsRectItem
        for i, val in enumerate(self.liste):
            width = self.col_w
            height = self.row_h * len(str(val)) + 1
            rectitem = rect_cls(0, 0, width, height, parent=self.item)
            rectitem.setX(seq_width)  # to give correct X to children item
            rectitem.setBrush(QBrush(QColor(self.bgcolor)))
            rectitem.setPen(nopen)

            # write letter if enough space in height
            if height >= self.fsize:
                text = QGraphicsSimpleTextItem(str(val), parent=rectitem)
                text.setFont(font)
                text.setBrush(QBrush(QColor(self.fgcolor)))
                # Center text according to rectitem size
                txtw = text.boundingRect().width() / 3.0
                txth = text.boundingRect().height()
                text.setRotation(self.rot)
                text.setX(txth * 1.5)
                #text.setY(0)
            seq_width += width
        self.width = seq_width
Ejemplo n.º 3
0
    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()
Ejemplo n.º 4
0
    def drawGrid(self):
        black_notes = [2,4,6,9,11]
        scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano)
        scale_bar.setPos(self.piano_width, 0)
        scale_bar.setBrush(QColor(100,100,100))
        clearpen = QPen(QColor(0,0,0,0))
        for i in range(self.end_octave - self.start_octave, self.start_octave - self.start_octave, -1):
            for j in range(self.notes_in_octave, 0, -1):
                scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano)
                scale_bar.setPos(self.piano_width, self.note_height * j + self.octave_height * (i - 1))
                scale_bar.setPen(clearpen)
                if j not in black_notes:
                    scale_bar.setBrush(QColor(120,120,120))
                else:
                    scale_bar.setBrush(QColor(100,100,100))

        measure_pen = QPen(QColor(0, 0, 0, 120), 3)
        half_measure_pen = QPen(QColor(0, 0, 0, 40), 2)
        line_pen = QPen(QColor(0, 0, 0, 40))
        for i in range(0, int(self.num_measures) + 1):
            measure = QGraphicsLineItem(0, 0, 0, self.piano_height + self.header_height - measure_pen.width(), self.header)
            measure.setPos(self.measure_width * i, 0.5 * measure_pen.width())
            measure.setPen(measure_pen)
            if i < self.num_measures:
                number = QGraphicsSimpleTextItem('%d' % (i + 1), self.header)
                number.setPos(self.measure_width * i + 5, 2)
                number.setBrush(Qt.white)
                for j in self.frange(0, self.time_sig[0]*self.grid_div/self.time_sig[1], 1.):
                    line = QGraphicsLineItem(0, 0, 0, self.piano_height, self.header)
                    line.setZValue(1.0)
                    line.setPos(self.measure_width * i + self.value_width * j, self.header_height)
                    if j == self.time_sig[0]*self.grid_div/self.time_sig[1] / 2.0:
                        line.setPen(half_measure_pen)
                    else:
                        line.setPen(line_pen)
Ejemplo n.º 5
0
    def _updateLabel(self, isLeft):
        """Called by updatePositionAndAppearance during init. Updates drawing
        and position of the label.

        Args:
            isLeft (TYPE): Description
        """
        lbl = self._label
        if self._idx is not None:
            if lbl is None:
                bw = _BASE_WIDTH
                num = self._partner_virtual_helix_id_num
                tbr = _FM.tightBoundingRect(str(num))
                half_label_h = tbr.height() / 2.0
                half_label_w = tbr.width() / 2.0
                # determine x and y positions
                labelX = bw / 2.0 - half_label_w
                if self.is_forward:
                    labelY = -0.25 * half_label_h - 0.5 - 0.5 * bw
                else:
                    labelY = 2 * half_label_h + 0.5 + 0.5 * bw
                # adjust x for left vs right
                labelXoffset = 0.25 * bw if isLeft else -0.25 * bw
                labelX += labelXoffset
                # adjust x for numeral 1
                if num == 1:
                    labelX -= half_label_w / 2.0
                # create text item
                lbl = QGraphicsSimpleTextItem(str(num), self)
                lbl.setPos(labelX, labelY)
                lbl.setBrush(_ENAB_BRUSH)
                lbl.setFont(_toHelixNumFont)
                self._label = lbl
            # end if
            lbl.setText(str(self._partner_virtual_helix_id_num))
Ejemplo n.º 6
0
    def __init__(self,
                 x,
                 y,
                 width=STATION_WIDTH,
                 height=STATION_HEIGHT,
                 name=""):

        # 此处的初始化 xy 值是以 item coordinate 标记矩形的起始点(左上角)
        super().__init__(-width / 2, -height / 2, width, height)

        # 此处的 xy 值是以 scene coordinate 标记矩形,结合上面的初始化,标记点是矩形的几何中心
        self.setPos(x, y)

        # 背景黑色
        self.setBrush(black_brush)

        # icon(相对于父 item 的 xy 值)
        QGraphicsPixmapItem(
            QPixmap(RM_path("./source/station.png")).scaled(
                ICON_WIDTH, ICON_HEIGHT), self).setPos(-width / 2 + 8,
                                                       -ICON_HEIGHT / 2)

        # name(相对于父 item 的 xy 值)
        name = QGraphicsSimpleTextItem(name, self)
        name.setBrush(white_brush)
        name.setFont(title_font)
        name.setPos(-width / 2 + 8 + ICON_WIDTH,
                    -name.boundingRect().height() / 2)
Ejemplo n.º 7
0
    def build_bonus_fields(self):
        for bonus_field in self._bonus_fields:
            brush = bonus_field["Brush"]
            pen = bonus_field["Pen"]
            bonus_fields = []

            for coords in bonus_field["Coords"]:
                label = bonus_field["Name"]
                if coords == Coords.central():
                    label = '✸'
                square = self._board_squares[coords]
                square.setZValue(2)
                bonus_fields.append(square)
                field_name = QGraphicsSimpleTextItem(label)
                font = field_name.font()
                font.setPointSize(10)
                if coords == Coords.central():
                    font.setPointSize(20)
                fm = QFontMetrics(font)
                field_name.setZValue(2.1)
                field_name.setFont(font)
                x = coords.x * SQUARE_SIZE + (SQUARE_SIZE - fm.width(label)) / 2
                y = coords.y * SQUARE_SIZE + (SQUARE_SIZE - fm.height()) / 2
                field_name.setPos(x, y)
                field_name.setBrush(bonus_field["Label brush"])

                self._labels[(x, y)] = field_name
                self.scene.addItem(field_name)

            paint_graphic_items(bonus_fields, pen, brush)
Ejemplo n.º 8
0
    def drawGrid(self):
        black_notes = [2,4,6,9,11]
        scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano)
        scale_bar.setPos(self.piano_width, 0)
        scale_bar.setBrush(QColor(100,100,100))
        clearpen = QPen(QColor(0,0,0,0))
        for i in range(self.end_octave - self.start_octave, self.start_octave - self.start_octave, -1):
            for j in range(self.notes_in_octave, 0, -1):
                scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano)
                scale_bar.setPos(self.piano_width, self.note_height * j + self.octave_height * (i - 1))
                scale_bar.setPen(clearpen)
                if j not in black_notes:
                    scale_bar.setBrush(QColor(120,120,120))
                else:
                    scale_bar.setBrush(QColor(100,100,100))

        measure_pen = QPen(QColor(0, 0, 0, 120), 3)
        half_measure_pen = QPen(QColor(0, 0, 0, 40), 2)
        line_pen = QPen(QColor(0, 0, 0, 40))
        for i in range(0, int(self.num_measures) + 1):
            measure = QGraphicsLineItem(0, 0, 0, self.piano_height + self.header_height - measure_pen.width(), self.header)
            measure.setPos(self.measure_width * i, 0.5 * measure_pen.width())
            measure.setPen(measure_pen)
            if i < self.num_measures:
                number = QGraphicsSimpleTextItem('%d' % (i + 1), self.header)
                number.setPos(self.measure_width * i + 5, 2)
                number.setBrush(Qt.white)
                for j in self.frange(0, self.time_sig[0]*self.grid_div/self.time_sig[1], 1.):
                    line = QGraphicsLineItem(0, 0, 0, self.piano_height, self.header)
                    line.setZValue(1.0)
                    line.setPos(self.measure_width * i + self.value_width * j, self.header_height)
                    if j == self.time_sig[0]*self.grid_div/self.time_sig[1] / 2.0:
                        line.setPen(half_measure_pen)
                    else:
                        line.setPen(line_pen)
Ejemplo n.º 9
0
class FloatingTextWidget(QGraphicsWidget):
    def __init__(self, parent=None, anchor="center"):
        QGraphicsWidget.__init__(self, parent)

        assert anchor in {"center", "corner"}
        self.anchor = anchor

        self._label = QGraphicsSimpleTextItem(self)
        self._label.setBrush(QColor(255, 255, 255))

        # Add drop shadow
        self._dropShadowEffect = QGraphicsDropShadowEffect()
        self.setGraphicsEffect(self._dropShadowEffect)

        self._dropShadowEffect.setOffset(0.0, 10.0)
        self._dropShadowEffect.setBlurRadius(8.0)
        self._dropShadowEffect.setColor(QColor(0, 0, 0, 50))

        self._spacingConstant = 5.0

    def updateLayout(self):
        width = self._label.boundingRect().width()
        height = self._label.boundingRect().height()

        width = self._spacingConstant + width + self._spacingConstant
        height = self._spacingConstant + height + self._spacingConstant

        self._label.setPos(self._spacingConstant, self._spacingConstant)

        self.resize(width, height)
        self.update()

    def paint(self, painter, option, widget):
        shape = QPainterPath()
        shape.addRoundedRect(self.rect(), 1, 1)

        painter.setBrush(QBrush(QColor(0, 0, 0)))
        painter.drawPath(shape)

        # painter.setPen(self._pen)
        # painter.drawPath(self._path)

    def onUpdated(self, center_position, text):
        self._label.setText(text)
        self.updateLayout()

        rect = self.rect()

        x_pos = center_position.x()
        y_pos = center_position.y()

        if self.anchor == "center":
            x_pos -= rect.width() / 2
            y_pos -= rect.height() / 2

        else:
            y_pos -= rect.height()

        self.setPos(x_pos, y_pos)
Ejemplo n.º 10
0
 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)
Ejemplo n.º 11
0
class WotNode(BaseNode):
    def __init__(self, nx_node, pos):
        """
        Create node in the graph scene

        :param tuple nx_node: Node info
        :param x_y: Position of the node
        """
        super().__init__(nx_node, pos)

        # color around ellipse
        outline_color = QColor('grey')
        outline_style = Qt.SolidLine
        outline_width = 1
        if self.status_wallet:
            outline_color = QColor('black')
            outline_width = 2
        if not self.status_member:
            outline_color = QColor('red')
            outline_style = Qt.SolidLine
        self.setPen(QPen(outline_color, outline_width, outline_style))

        # text inside ellipse
        self.text_item = QGraphicsSimpleTextItem(self)
        self.text_item.setText(self.text)
        text_color = QColor('grey')
        if self.status_wallet == NodeStatus.HIGHLIGHTED:
            text_color = QColor('black')
        self.text_item.setBrush(QBrush(text_color))
        # center ellipse around text
        self.setRect(0, 0,
                     self.text_item.boundingRect().width() * 2,
                     self.text_item.boundingRect().height() * 2)

        #  set anchor to the center
        self.setTransform(QTransform().translate(
            -self.boundingRect().width() / 2.0,
            -self.boundingRect().height() / 2.0))
        # center text in ellipse
        self.text_item.setPos(self.boundingRect().width() / 4.0,
                              self.boundingRect().height() / 4.0)

        # create gradient inside the ellipse
        gradient = QRadialGradient(
            QPointF(0,
                    self.boundingRect().height() / 4),
            self.boundingRect().width())
        gradient.setColorAt(0, QColor('white'))
        gradient.setColorAt(1, QColor('darkgrey'))
        self.setBrush(QBrush(gradient))

        # cursor change on hover
        self.setAcceptHoverEvents(True)
        self.setZValue(1)
Ejemplo n.º 12
0
class BasicNode(QGraphicsItemGroup):
    def __init__(self, model, manager, text_color=Qt.black):
        bg_color = model.get_bg_color()
        super(BasicNode, self).__init__()
        self.model = model
        text = model.get_display_text()
        self.manager = manager
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemIsFocusable, True)

        self.text_graph = QGraphicsSimpleTextItem(text)
        self.text_graph.setBrush(text_color)
        bound = self.text_graph.boundingRect()
        r = QPointF(bound.width() / 2, bound.height() / 2)
        text_center = self.text_graph.pos() + r
        self.text_graph.setPos(-text_center)
        self.addToGroup(self.text_graph)

        self.box_graph = BoxOutline(bg_color)
        empty_space = QPointF(UNIT, UNIT)
        newr = (empty_space + r)
        self.box_graph.rect = QRectF(-newr, newr)
        self.addToGroup(self.box_graph)
        self.text_graph.setZValue(1.0)
        self.box_graph.setZValue(0.0)

        self.children = []

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemSelectedChange:
            self.manager.selection_changed(self, value)
            return value
        else:
            return super(BasicNode, self).itemChange(change, value)

    def get_width(self):
        return self.boundingRect().width()

    def set_left_pos(self, pos):
        pos += QPoint(self.get_width() / 2.0, 0)
        self.setPos(pos)

    def left_pos(self):
        return self.pos() - QPointF(self.get_width() / 2.0, 0)

    def center_pos(self):
        return self.pos()

    def right_pos(self):
        return self.pos() + QPointF(self.get_width() / 2.0, 0)

    """
Ejemplo n.º 13
0
class BasicNode(QGraphicsItemGroup):
    def __init__(self, model, manager, text_color=Qt.black):
        bg_color = model.get_bg_color()
        super(BasicNode, self).__init__()
        self.model = model
        text = model.get_display_text()
        self.manager = manager
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemIsFocusable, True)

        self.text_graph = QGraphicsSimpleTextItem(text)
        self.text_graph.setBrush(text_color)
        bound = self.text_graph.boundingRect()
        r = QPointF(bound.width() / 2, bound.height() / 2)
        text_center = self.text_graph.pos() + r
        self.text_graph.setPos(-text_center)
        self.addToGroup(self.text_graph)

        self.box_graph = BoxOutline(bg_color)
        empty_space = QPointF(UNIT, UNIT)
        newr = (empty_space + r)
        self.box_graph.rect = QRectF(-newr, newr)
        self.addToGroup(self.box_graph)
        self.text_graph.setZValue(1.0)
        self.box_graph.setZValue(0.0)

        self.children = []

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemSelectedChange:
            self.manager.selection_changed(self, value)
            return value
        else:
            return super(BasicNode, self).itemChange(change, value)

    def get_width(self):
        return self.boundingRect().width()

    def set_left_pos(self, pos):
        pos += QPoint(self.get_width() / 2.0, 0)
        self.setPos(pos)

    def left_pos(self):
        return self.pos() - QPointF(self.get_width() / 2.0, 0)

    def center_pos(self):
        return self.pos()

    def right_pos(self):
        return self.pos() + QPointF(self.get_width() / 2.0, 0)

    """
Ejemplo n.º 14
0
class WotNode(BaseNode):
    def __init__(self, nx_node, pos):
        """
        Create node in the graph scene

        :param tuple nx_node: Node info
        :param x_y: Position of the node
        """
        super().__init__(nx_node, pos)

        # color around ellipse
        outline_color = QColor('grey')
        outline_style = Qt.SolidLine
        outline_width = 1
        if self.status_wallet:
            outline_color = QColor('black')
            outline_width = 2
        if not self.status_member:
            outline_color = QColor('red')
            outline_style = Qt.SolidLine
        self.setPen(QPen(outline_color, outline_width, outline_style))

        # text inside ellipse
        self.text_item = QGraphicsSimpleTextItem(self)
        self.text_item.setText(self.text)
        text_color = QColor('grey')
        if self.status_wallet == NodeStatus.HIGHLIGHTED:
            text_color = QColor('black')
        self.text_item.setBrush(QBrush(text_color))
        # center ellipse around text
        self.setRect(
            0,
            0,
            self.text_item.boundingRect().width() * 2,
            self.text_item.boundingRect().height() * 2
        )

        #  set anchor to the center
        self.setTransform(
            QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0))
        # center text in ellipse
        self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0)

        # create gradient inside the ellipse
        gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width())
        gradient.setColorAt(0, QColor('white'))
        gradient.setColorAt(1, QColor('darkgrey'))
        self.setBrush(QBrush(gradient))

        # cursor change on hover
        self.setAcceptHoverEvents(True)
        self.setZValue(1)
Ejemplo n.º 15
0
    def create_chan_labels(self):
        """Create the channel labels, but don't plot them yet.

        Notes
        -----
        It's necessary to have the width of the labels, so that we can adjust
        the main scene.
        """
        self.idx_label = []
        for one_grp in self.parent.channels.groups:
            for one_label in one_grp['chan_to_plot']:
                item = QGraphicsSimpleTextItem(one_label)
                item.setBrush(QBrush(QColor(one_grp['color'])))
                item.setFlag(QGraphicsItem.ItemIgnoresTransformations)
                self.idx_label.append(item)
Ejemplo n.º 16
0
    def create_chan_labels(self):
        """Create the channel labels, but don't plot them yet.

        Notes
        -----
        It's necessary to have the width of the labels, so that we can adjust
        the main scene.
        """
        self.idx_label = []
        for one_grp in self.parent.channels.groups:
            for one_label in one_grp['chan_to_plot']:
                item = QGraphicsSimpleTextItem(one_label)
                item.setBrush(QBrush(QColor(one_grp['color'])))
                item.setFlag(QGraphicsItem.ItemIgnoresTransformations)
                self.idx_label.append(item)
Ejemplo n.º 17
0
 def __init__(self, i, video_item):
     self.video_item = video_item
     scene = QGraphicsScene()
     super().__init__(scene)
     self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
     self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
     self.setStyleSheet("border-style: none")
     scene.setBackgroundBrush(QBrush(Qt.black))
     scene.addItem(video_item)
     text = QGraphicsSimpleTextItem(str(i + 1))
     font = QFont("Helvetica", 48)
     brush = QBrush(QColor.fromRgb(255, 255, 0))
     text.setBrush(brush)
     text.setFont(font)
     text.setPos(50, 50)
     scene.addItem(text)
Ejemplo n.º 18
0
    def build_exchange_zone(self):
        brush = QBrush(LIGHT_BROWN)
        pen = QPen(BROWN, 1, Qt.SolidLine)
        for column in range(LEFT_RACK_BOUND, RIGHT_RACK_BOUND + 1):
            square = self.add_square(EXCHANGE_ROW, column, pen, brush)
            self._other_squares[Coords(column, EXCHANGE_ROW)] = square

        text = 'Litery do wymiany →     '
        font = QFont('Verdana', 10)
        fm = QFontMetrics(font)
        x = SQUARE_SIZE * LEFT_RACK_BOUND - fm.width(text)
        y = SQUARE_SIZE * EXCHANGE_ROW + (SQUARE_SIZE - fm.height()) / 2
        label = QGraphicsSimpleTextItem(text)
        label.setPos(x, y)
        label.setFont(font)
        label.setBrush(QBrush(Qt.white))
        self._labels[(x, y)] = label
        self.scene.addItem(label)
Ejemplo n.º 19
0
 def updateGraphicsSimpleTextItem(textItem: QGraphicsSimpleTextItem, text: str = None, color: QColor = None,
                                  pos: QPointF = None, fontSize: int = 18):
     """
     更新普通文本QGraphicsSimpleTextItem属性
     :param textItem: QGraphicsSimpleTextItem
     :param text: 显示文字
     :param color: 文字颜色
     :param pos: 文字位置
     :param fontSize: 字体大小
     """
     if text:
         textItem.setText(text)
     if fontSize:
         font = QFont()
         font.setPointSize(fontSize)
         textItem.setFont(font)
     if color:
         textItem.setBrush(color)
     if pos:
         textItem.setPos(pos)
Ejemplo n.º 20
0
    def init_ui(self):

        scene = QGraphicsScene()
        scene.setBackgroundBrush(QColor(100, 100, 100))
        scene.setItemIndexMethod(QGraphicsScene.BspTreeIndex)

        scene.setSceneRect(scene.itemsBoundingRect())

        self.setDragMode(QGraphicsView.RubberBandDrag)
        self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)
        self.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing)

        self.frame_item = QGraphicsPixmapItem()

        self.text_item_offset = 0
        self.rect_item_array = []
        self.text_item_array = []
        for i in range(0, 5):
            rect_item = QGraphicsRectItem()
            rect_item.setVisible(False)
            rect_item.setZValue(20.0)
            rect_item.setPen(QPen(Qt.red, 5))
            rect_item.setRect(20, 20, 20, 20)
            scene.addItem(rect_item)
            self.rect_item_array.append(rect_item)
            text_item = QGraphicsSimpleTextItem("")
            text_item.setBrush(QBrush(Qt.red))
            text_item.setZValue(20.0)
            text_item.setPos(10, 50)
            text_item.setFont(QFont("黑体", 24))
            text_item.setVisible(False)
            scene.addItem(text_item)
            self.text_item_array.append(text_item)

        scene.addItem(self.frame_item)

        self.curr_factor = 1.0

        self.setScene(scene)
Ejemplo n.º 21
0
    def init_ui(self):

        scene = QGraphicsScene()
        scene.setBackgroundBrush(QColor(100, 100, 100))
        scene.setItemIndexMethod(QGraphicsScene.BspTreeIndex)

        scene.setSceneRect(scene.itemsBoundingRect())

        self.setDragMode(QGraphicsView.RubberBandDrag)
        self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)
        self.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing)

        self.frame_item = QGraphicsPixmapItem()

        self.text_item_offset = 0
        self.rect_item_array = []
        self.text_item_array = []
        for i in range(0, 5):
            rect_item = QGraphicsRectItem()
            rect_item.setVisible(False)
            rect_item.setZValue(20.0)
            rect_item.setPen(QPen(Qt.red, 5))
            rect_item.setRect(20, 20, 20, 20)
            scene.addItem(rect_item)
            self.rect_item_array.append(rect_item)
            text_item = QGraphicsSimpleTextItem("")
            text_item.setBrush(QBrush(Qt.red))
            text_item.setZValue(20.0)
            text_item.setPos(10, 50)
            text_item.setFont(QFont("黑体", 32))
            text_item.setVisible(False)
            scene.addItem(text_item)
            self.text_item_array.append(text_item)

        scene.addItem(self.frame_item)

        self.curr_factor = 1.0

        self.setScene(scene)
Ejemplo n.º 22
0
    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()
Ejemplo n.º 23
0
    def build_labels(self):
        font = QFont('Verdana', 10)
        fm = QFontMetrics(font)
        for count in range(LAST_ROW + 1):
            number = str(count + 1)
            number_label = QGraphicsSimpleTextItem(number)
            x = -fm.width(number) - SQUARE_SIZE / 8
            y = count * SQUARE_SIZE + (SQUARE_SIZE - fm.height()) / 2
            number_label.setPos(x, y)
            number_label.setFont(font)
            number_label.setBrush(QBrush(Qt.white))
            self._labels[(x, y)] = number_label

            letter = chr(count + ord('A'))
            letter_label = QGraphicsSimpleTextItem(letter)
            x = count * SQUARE_SIZE + (SQUARE_SIZE - fm.width(letter)) / 2
            y = -fm.height() - SQUARE_SIZE / 8
            letter_label.setPos(x, y)
            letter_label.setFont(font)
            letter_label.setBrush(QBrush(Qt.white))
            self._labels[(x, y)] = letter_label

            self.scene.addItem(number_label)
            self.scene.addItem(letter_label)
Ejemplo n.º 24
0
class DigitalClock(Desklet):

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

        self.seconds = QGraphicsSimpleTextItem(self.root)
        self.time = QGraphicsSimpleTextItem(self.root)
        self.date = QGraphicsSimpleTextItem(self.root)

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

        self.seconds.setBrush(style.foreground_color)
        self.time.setBrush(style.foreground_color)
        self.date.setBrush(style.foreground_color)

        font = QFont(style.font)
        font.setPixelSize(192 * 0.5)
        self.seconds.setFont(font)

        font = QFont(style.font)
        font.setPixelSize(192 * 0.75)
        self.time.setFont(font)

        font = QFont(style.font)
        font.setPixelSize(56)
        self.date.setFont(font)
        self.layout()

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

    def layout(self):
        time_fm = QFontMetrics(self.time.font())
        seconds_fm = QFontMetrics(self.seconds.font())

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

        self.time.setPos(x, y)
        self.seconds.setPos(x + time_fm.width("00:00") + 20,
                            y + time_fm.ascent() - seconds_fm.ascent())
        self.date.setPos(x, y + time_fm.ascent())

    def update(self, now):
        date = now.strftime("%A, %d. %B %Y")
        time = now.strftime("%H:%M")
        seconds = now.strftime("%S")

        self.time.setText(time)
        self.seconds.setText(seconds)
        self.date.setText(date)
Ejemplo n.º 25
0
class StopWatch(Desklet):

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

        self.timer = Timer()
        self.timeout_handle = None

        self.qtimer = QTimer()
        self.qtimer.timeout.connect(self.my_update)

        self.label = QGraphicsSimpleTextItem("Stopwatch:", self.root)
        self.time = QGraphicsSimpleTextItem("00:00", self.root)
        self.seconds = QGraphicsSimpleTextItem("00'00", self.root)

    def update(self):
        t = self.timer.get_time()
        time = "%02d:%02d" % (t.seconds / (60 * 60), (t.seconds % (60 * 60)) / 60)
        seconds = "%02d'%02d" % (t.seconds % 60, t.microseconds / 10000)

        self.time.setText(time)
        self.seconds.setText(seconds)

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

        font = QFont(style.font)
        font.setPixelSize(24)
        self.time.setFont(font)
        self.label.setFont(font)

        font = QFont(style.font)
        font.setPixelSize(192 / 2)
        self.time.setFont(font)

        font = QFont(style.font)
        font.setPixelSize(192 / 2 * 0.6)
        self.seconds.setFont(font)

        self.label.setBrush(self.style.foreground_color)
        self.time.setBrush(self.style.foreground_color)
        self.seconds.setBrush(self.style.foreground_color)

        self.layout()

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

    def layout(self):
        x = self.rect.left()
        y = self.rect.top()

        fm = QFontMetrics(self.time.font())
        rect = fm.boundingRect("00:00")

        sfm = QFontMetrics(self.seconds.font())

        self.time.setPos(x, y + 20)
        self.seconds.setPos(x + 20 + rect.width(), y + 20 + fm.ascent() - sfm.ascent())

        self.label.setPos(x, y)

    def my_update(self):
        self.update()

    def is_running(self):
        return self.timer.is_running()

    def start_stop_watch(self):
        self.timer.start_stop()

        if self.timer.is_running():
            self.qtimer.setInterval(31)
            self.qtimer.start()
        else:
            self.qtimer.stop()

    def clear_stop_watch(self):
        self.timer.reset()
Ejemplo n.º 26
0
class ExplorerNode(BaseNode):
    def __init__(self, nx_node, center_pos, nx_pos, steps, steps_max, small):
        """
        Create node in the graph scene

        :param tuple nx_node: Node info
        :param center_pos: The position of the center node
        :param nx_pos: Position of the nodes in the graph
        :param int steps: The steps from the center identity
        :param int steps_max: The steps max of the graph
        :param bool small: Small dots for big networks
        """
        super().__init__(nx_node, nx_pos)

        self.steps = steps
        self.steps_max = steps_max
        self.highlighted = False
        self.status_sentry = False

        if small:
            self.setRect(0, 0, 10, 10)
            self.text_item = None
        else:
            # text inside ellipse
            self.text_item = QGraphicsSimpleTextItem(self)
            self.text_item.setText(self.text)
            # center ellipse around text
            self.setRect(0, 0,
                         self.text_item.boundingRect().width() * 2,
                         self.text_item.boundingRect().height() * 2)
            # center text in ellipse
            self.text_item.setPos(self.boundingRect().width() / 4.0,
                                  self.boundingRect().height() / 4.0)

        #  set anchor to the center
        self.setTransform(QTransform().translate(
            -self.boundingRect().width() / 2.0,
            -self.boundingRect().height() / 2.0))

        # cursor change on hover
        self.setAcceptHoverEvents(True)
        self.setZValue(1)

        # animation and moves
        self.timeline = None
        self.loading_timer = QTimer()
        self.loading_timer.timeout.connect(self.next_tick)
        self.loading_counter = 0
        self._refresh_colors()
        self.setPos(center_pos)
        self.move_to(nx_pos)

    def update_metadata(self, metadata):
        super().update_metadata(metadata)
        self.status_sentry = self.metadata[
            'is_sentry'] if 'is_sentry' in self.metadata else False
        self._refresh_colors()

    def _refresh_colors(self):
        """
        Refresh elements in the node
        """
        # color around ellipse
        outline_color = QColor('grey')
        outline_style = Qt.SolidLine
        outline_width = 1
        if self.status_wallet:
            outline_width = 2
        if not self.status_member:
            outline_color = QColor('red')

        if self.status_sentry:
            outline_color = QColor('black')
            outline_width = 3

        self.setPen(QPen(outline_color, outline_width, outline_style))

        if self.highlighted:
            text_color = QColor('grey')
        else:
            text_color = QColor('black')

        if self.status_wallet == NodeStatus.HIGHLIGHTED:
            text_color = QColor('grey')

        if self.text_item:
            self.text_item.setBrush(QBrush(text_color))

        # create gradient inside the ellipse
        gradient = QRadialGradient(
            QPointF(0,
                    self.boundingRect().height() / 4),
            self.boundingRect().width())
        color = QColor()
        color.setHsv(120 - 60 / self.steps_max * self.steps,
                     180 + 50 / self.steps_max * self.steps,
                     60 + 170 / self.steps_max * self.steps)
        if self.highlighted:
            color = color.darker(200)
        color = color.lighter(
            math.fabs(math.sin(self.loading_counter / 100 * math.pi) * 100) +
            100)
        gradient.setColorAt(0, color)
        gradient.setColorAt(1, color.darker(150))
        self.setBrush(QBrush(gradient))

    def move_to(self, nx_pos):
        """
        Move to corresponding position
        :param nx_pos:
        :return:
        """
        origin_x = self.x()
        origin_y = self.y()
        final_x = nx_pos[self.id][0]
        final_y = nx_pos[self.id][1]

        def frame_move(frame):
            value = self.timeline.valueForTime(self.timeline.currentTime())
            x = origin_x + (final_x - origin_x) * value
            y = origin_y + (final_y - origin_y) * value
            self.setPos(x, y)
            if self.scene():
                self.scene().node_moved.emit(self.id, x, y)

        def timeline_ends():
            self.setPos(final_x, final_y)
            self.timeline = None

        # Remember to hold the references to QTimeLine and QGraphicsItemAnimation instances.
        # They are not kept anywhere, even if you invoke QTimeLine.start().
        self.timeline = QTimeLine(1000)
        self.timeline.setFrameRange(0, 100)
        self.timeline.frameChanged.connect(frame_move)
        self.timeline.finished.connect(timeline_ends)

        self.timeline.start()

    def highlight(self):
        """
        Highlight the edge in the scene
        """
        self.highlighted = True
        self._refresh_colors()
        self.update(self.boundingRect())

    def neutralize(self):
        """
        Neutralize the edge in the scene
        """
        self.highlighted = False
        self._refresh_colors()
        self.update(self.boundingRect())

    def start_loading_animation(self):
        """
        Neutralize the edge in the scene
        """
        if not self.loading_timer.isActive():
            self.loading_timer.start(10)

    def stop_loading_animation(self):
        """
        Neutralize the edge in the scene
        """
        self.loading_timer.stop()
        self.loading_counter = 100
        self._refresh_colors()
        self.update(self.boundingRect())

    def next_tick(self):
        """
        Next tick
        :return:
        """
        self.loading_counter += 1
        self.loading_counter %= 100
        self._refresh_colors()
        self.update(self.boundingRect())
Ejemplo n.º 27
0
class Tile(Pixmap):
    """ Tile class defines on screen tiles """

    anim_complete = pyqtSignal()  # Signal for completion of animation
    sheet = None  # Sprite sheet

    def __init__(self, letter, scene, letfile=r"\scrabble_letters.png"):

        self.alphabet = scene.alphabet
        if type(self).sheet is None:
            type(self).sheet = QPixmap(self.alphabet.lang + letfile)

        # Extract letter tile from sheet, scale to cell size for board
        image = type(self).sheet.copy(self.alphabet.TILE_POSITIONS[letter][0],
                                      self.alphabet.TILE_POSITIONS[letter][1],
                                      Cons.TILE_WIDTH, Cons.TILE_HEIGHT)
        image = image.scaled(Cons.WIDTH, Cons.HEIGHT, Qt.IgnoreAspectRatio,
                             Qt.SmoothTransformation)
        super(Tile, self).__init__(image)

        type(self).sheet = None
        self.letter = letter
        self.blank_letter = None
        self.rack_pos = QPointF()
        self.pos = QPointF()
        self.txt = None
        self.scene = scene
        self.alphabet = self.scene.alphabet

        self.pixmap_item.setFlags(QGraphicsItem.ItemIsSelectable
                                  | QGraphicsItem.ItemIsMovable)
        self.pixmap_item.setTransform(QTransform())
        self.pixmap_item.setAcceptedMouseButtons(Qt.LeftButton)
        self.pixmap_item.setZValue(1000)
        self.pixmap_item.letter = letter
        self.pixmap_item.tile = self
        self.pixmap_item.hide()
        # self.add_to_scene(self.scene)
        self.scene.addItem(self.pixmap_item)
        self.pos = QPointF(0, 0)
        self.animation = None
        self.fade = None

    # Draw at position (QPoint) on screen
    def draw_tile(self, position):
        """ Extract letter tile from sheet, scale to cell size for board
            draw at (xpos, ypos) """
        self.pos = position
        self.pixmap_item.show()

    def get_pos(self):
        """ Return position of tile """
        return self.pixmap_item.pos()

    def set_pos(self, x, y):
        """ Move tile to position (x, y) """
        self.pixmap_item.setPos(x, y)

    def hand_cursor(self):
        """ Change cursor to hand cursor """
        self.pixmap_item.setCursor(Qt.PointingHandCursor)

    def reset_cursor(self):
        """ Change cursor to pointer cursor """
        self.pixmap_item.setCursor(Qt.ArrowCursor)

    def move_tile(self, dur, *args):
        """ Create move tile animation
            *args are time fraction, points in path either as
            (time, QPointF) or (time, x, y) """
        if not self.pixmap_item.isVisible():
            self.pixmap_item.setPos(
                QPointF(Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2,
                        Cons.WINDOW_SIZE[1]))
            self.pixmap_item.show()
        animation = QPropertyAnimation(self, b'pos')
        animation.setDuration(dur)
        for val in args:
            if isinstance(val[1], QPointF):
                point = val[1]
            else:
                point = QPointF(val[1], val[2])
            animation.setKeyValueAt(val[0], point)
        self.animation = animation
        return self.animation

    def activate(self, activate):
        """ Accept mouse presses if activate is True """
        if activate:
            self.pixmap_item.setAcceptedMouseButtons(Qt.LeftButton)
        else:
            self.pixmap_item.setAcceptedMouseButtons(Qt.NoButton)

    def dim(self, activate):
        """ Dim tile if activate is True """
        if activate:
            self.pixmap_item.setOpacity(0.4)
        else:
            self.pixmap_item.setOpacity(1)

    def set_in_board(self):
        """ Set tile in board
            No longer moveable """
        self.pixmap_item.setAcceptedMouseButtons(Qt.NoButton)

    def add_letter(self, letter):
        """ Add small letter to blank tile """

        self.txt = QGraphicsSimpleTextItem(letter, self.pixmap_item)
        self.txt.setFont(QFont("Arial", 14, QFont.DemiBold))
        self.txt.setBrush(QBrush(Qt.darkRed))
        wd, ht = self.txt.boundingRect().width(), self.txt.boundingRect(
        ).height()
        self.txt.setPos((Cons.WIDTH - wd) / 2, (Cons.HEIGHT - ht) / 2)

    def get_tile(self):
        """ Move tile from store (bottom centre) to position on rack
            Used in Group Animation """
        return self.move_tile(
            1000,
            (0, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, Cons.WINDOW_SIZE[1]),
            (0.2, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, self.rack_pos.y()),
            (1, self.rack_pos))

    def return_tile(self):
        """ Return tile to rack
            Used in Group Animation """
        return self.move_tile(400, (0, self.get_pos()), (1, self.rack_pos))

    def remove_tile(self):
        """ Remove tile from board
            Used in Group Animation """
        return self.move_tile(
            1000, (0, self.get_pos()),
            (0.8, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2,
             self.get_pos().y()),
            (1, Cons.WINDOW_SIZE[0] / 2 - Cons.WIDTH / 2, Cons.WINDOW_SIZE[1]))

    def lift_tile(self):
        """ Used in exchange tiles
            Lift chosen tile to set position above rack """
        self.animation = self.move_tile(
            100, (0, self.rack_pos),
            (1, self.rack_pos + QPointF(0, Cons.TILE_LIFT)))
        self.animation.start()

    def drop_tile(self):
        """ Used in exchange tiles
            Drop chosen tile back into rack """
        self.animation = self.move_tile(100, (0, self.get_pos()),
                                        (1, self.rack_pos))
        self.animation.start()

    def name_tile(self, player):
        """ Used in names screen
            Move chosen blank tiles to required position """
        point = QPointF(
            Cons.INPUT_NAMES[player][0] + Cons.INPUT_NAMES[player][2],
            Cons.INPUT_NAMES[player][1] + 50)
        self.animation = self.move_tile(100, (0, self.get_pos()), (1, point))
        self.animation.start()

    def return_blank(self):
        """ Used in names screen
            Return tile to position on board """
        self.animation = self.move_tile(400, (0, self.get_pos()),
                                        (1, self.rack_pos))
        self.animation.start()

    def unfade(self):
        """ Fade in letter on blank tile """
        self.fade = QPropertyAnimation(self, b'opacity')
        self.fade.setDuration(2000)
        self.fade.setStartValue(0)
        self.fade.setEndValue(1)
        self.fade.setEasingCurve(QEasingCurve.InOutSine)
        self.fade.finished.connect(self._fade_end)
        self.fade.start()

    def _fade_end(self):
        """ end of animation """
        self.anim_complete.emit()

    def hide(self):
        """ Hide tile """
        self.pixmap_item.hide()

    def setZValue(self, val):
        """ set ZValue for image """
        self.pixmap_item.setZValue(val)
Ejemplo n.º 28
0
class StickWidget(QGraphicsObject):

    font: QFont = QFont("monospace", 32)

    delete_clicked = pyqtSignal(Stick)
    link_initiated = pyqtSignal('PyQt_PyObject') # Actually StickWidget
    link_accepted = pyqtSignal('PyQt_PyObject')
    hovered = pyqtSignal(['PyQt_PyObject', 'PyQt_PyObject'])
    stick_changed = pyqtSignal('PyQt_PyObject')
    sibling_changed = pyqtSignal(bool)
    right_clicked = pyqtSignal('PyQt_PyObject')

    handle_idle_brush = QBrush(QColor(0, 125, 125, 50))
    handle_hover_brush = QBrush(QColor(125, 125, 0, 50))
    handle_press_brush = QBrush(QColor(200, 200, 0, 0))
    handle_idle_pen = QPen(QColor(0, 0, 0, 255))
    handle_press_pen = QPen(QColor(200, 200, 0, 255))
    handle_size = 20

    normal_color = QColor(0, 200, 120)
    negative_color = QColor(200, 0, 0)
    positive_color = QColor(0, 200, 0)

    mismatched = pyqtSignal('PyQt_PyObject')
    misplaced = pyqtSignal('PyQt_PyObject')
    measurement_corrected = pyqtSignal('PyQt_PyObject')
    clearly_visible = pyqtSignal('PyQt_PyObject')
    zero_clicked = pyqtSignal('PyQt_PyObject')

    def __init__(self, stick: Stick, camera: Camera, parent: Optional[QGraphicsItem] = None):
        QGraphicsObject.__init__(self, parent)
        self.camera = camera
        self.stick = stick
        self.line = QLineF()
        self.gline = QGraphicsLineItem(self.line)

        self.stick_label_text = QGraphicsSimpleTextItem("0", self)
        self.stick_label_text.setFont(StickWidget.font)
        self.stick_label_text.setPos(self.line.p1() - QPoint(0, 24))
        self.stick_label_text.setBrush(QBrush(QColor(0, 255, 0)))
        self.stick_label_text.hide()
        self.setZValue(10)

        self.mode = StickMode.Display

        self.btn_delete = Button("delete", "x", parent=self)
        self.btn_delete.setFlag(QGraphicsItem.ItemIgnoresTransformations, True)
        self.btn_delete.set_base_color([ButtonColor.RED])
        self.btn_delete.setVisible(False)
        btn_size = max(int(np.linalg.norm(self.stick.top - self.stick.bottom) / 5.0), 15)
        self.btn_delete.set_height(12)
        self.btn_delete.clicked.connect(self.handle_btn_delete_clicked)
        self.btn_delete.setPos(self.line.p1() - QPointF(0.5 * self.btn_delete.boundingRect().width(), 1.1 * self.btn_delete.boundingRect().height()))
        self.btn_delete.set_opacity(0.7)

        self.top_handle = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self)
        self.mid_handle = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self)
        self.bottom_handle = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self)

        self.top_handle.setAcceptedMouseButtons(Qt.NoButton)
        self.mid_handle.setAcceptedMouseButtons(Qt.NoButton)
        self.bottom_handle.setAcceptedMouseButtons(Qt.NoButton)
        self.top_handle.setBrush(self.handle_idle_brush)
        self.top_handle.setPen(self.handle_idle_pen)
        self.mid_handle.setBrush(self.handle_idle_brush)
        self.mid_handle.setPen(self.handle_idle_pen)
        self.bottom_handle.setBrush(self.handle_idle_brush)
        self.bottom_handle.setPen(self.handle_idle_pen)

        self.hovered_handle: Optional[QGraphicsRectItem] = None
        self.handles = [self.top_handle, self.mid_handle, self.bottom_handle]

        self.link_button = Button("link", "Link to...", parent=self)
        self.link_button.set_base_color([ButtonColor.GREEN])
        self.link_button.set_height(12)
        self.link_button.set_label("Link", direction="vertical")
        self.link_button.fit_to_contents()
        self.link_button.clicked.connect(lambda: self.link_initiated.emit(self))
        self.link_button.setVisible(False)
        self.link_button.setFlag(QGraphicsObject.ItemIgnoresTransformations, False)

        self.adjust_line()

        self.setAcceptHoverEvents(True)
        self.top_handle.setZValue(4)
        self.bottom_handle.setZValue(4)
        self.mid_handle.setZValue(4)

        self.top_handle.hide()
        self.mid_handle.hide()
        self.bottom_handle.hide()

        self.handle_mouse_offset = QPointF(0, 0)
        self.available_for_linking = False
        self.link_source = False
        self.current_highlight_color: QColor = StickWidget.normal_color
        self.highlighted = False
        self.frame_color: Optional[None] = self.normal_color
        self.is_linked = False

        self.is_master = True
        self.selected = False

        self.measured_height: int = -1
        self.current_color = self.normal_color

        self.show_label = False
        self.highlight_animation = QPropertyAnimation(self, b"highlight_color")
        self.highlight_animation.valueChanged.connect(self.handle_highlight_animation_value_changed)
        self.deleting = False
        self.update_tooltip()
        self.show_measurements: bool = False
        self.proposed_snow_height: int = -1

        self.zero_btn = Button("zero_btn", "0", parent=self)
        self.zero_btn.setFlag(QGraphicsItem.ItemIgnoresTransformations, True)
        self.zero_btn.setVisible(False)
        self.zero_btn.setPos(self.boundingRect().center() + QPointF(self.zero_btn.boundingRect().width() * -0.5,
                                                                    self.boundingRect().height() * 0.5))
        self.zero_btn.clicked.connect(self.handle_zero)

    @pyqtSlot()
    def handle_btn_delete_clicked(self):
        self.delete_clicked.emit(self.stick)

    def prepare_for_deleting(self):
        self.deleting = True
        self.highlight_animation.stop()
        self.btn_delete.setParentItem(None)
        self.scene().removeItem(self.btn_delete)
        self.btn_delete.deleteLater()

    def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem,
              widget: Optional[PyQt5.QtWidgets.QWidget] = ...):
        painter.setPen(QPen(self.current_color, 1.0))

        brush = QBrush(self.current_highlight_color)
        pen = QPen(brush, 4)
        painter.setPen(pen)
        if self.highlighted:
            painter.fillRect(self.boundingRect(), QBrush(self.current_highlight_color))

        if self.frame_color is not None and self.mode != StickMode.Edit and self.mode != StickMode.EditDelete:
            painter.setPen(QPen(self.frame_color, 4))
            painter.drawRect(self.boundingRect())

        pen = QPen(QColor(0, 255, 0, 255))

        pen.setWidth(1.0)
        pen.setColor(QColor(255, 0, 255, 255))
        pen.setStyle(Qt.DotLine)
        painter.setPen(pen)
        off = 10
        painter.drawLine(self.line.p1() - QPointF(0, off), self.line.p1() + QPointF(0, off))
        painter.drawLine(self.line.p1() - QPointF(off, 0), self.line.p1() + QPointF(off, 0))
        painter.drawLine(self.line.p2() - QPointF(0, off), self.line.p2() + QPointF(0, off))
        painter.drawLine(self.line.p2() - QPointF(off, 0), self.line.p2() + QPointF(off, 0))
        pen.setStyle(Qt.SolidLine)
        pen.setColor(QColor(0, 255, 0, 255))
        painter.setPen(pen)

        if self.mode != StickMode.EditDelete:
            pen.setWidth(2.0)
            br = painter.brush()
            painter.setPen(pen)
            painter.drawEllipse(self.line.p1(), 10, 10)
            painter.drawEllipse(self.line.p2(), 10, 10)
            painter.setBrush(br)

            if self.mode == StickMode.Measurement and self.proposed_snow_height >= 0:
                point = QPointF(self.boundingRect().x(), -self.proposed_snow_height + self.line.p2().y())
                pen = QPen(QColor(200, 100, 0, 255), 3.0)
                painter.setPen(pen)
                painter.drawLine(point,
                                 point + QPointF(self.boundingRect().width(), 0.0))

            if self.measured_height >= 0:
                vec = (self.stick.top - self.stick.bottom) / np.linalg.norm(self.stick.top - self.stick.bottom)
                dist_along_stick = self.measured_height / np.dot(np.array([0.0, -1.0]), vec)
                point = self.line.p2() + dist_along_stick * QPointF(vec[0], vec[1])
                point = QPointF(self.boundingRect().x(), point.y())
                pen = QPen(QColor(0, 100, 200, 255), 3.0)
                painter.setPen(pen)
                painter.drawLine(point,
                                 point + QPointF(self.boundingRect().width(), 0.0))
        else:
            painter.drawLine(self.line.p1(), self.line.p2())

        if self.selected:
            pen.setColor(QColor(255, 125, 0, 255))
            pen.setStyle(Qt.DashLine)
            painter.setPen(pen)
            painter.drawRect(self.boundingRect().marginsAdded(QMarginsF(5, 5, 5, 5)))

        if self.show_measurements:
            painter.fillRect(self.stick_label_text.boundingRect().translated(self.stick_label_text.pos()),
                             QBrush(QColor(0, 0, 0, 120)))

    def boundingRect(self) -> PyQt5.QtCore.QRectF:
        return self.gline.boundingRect().united(self.top_handle.boundingRect()).\
            united(self.mid_handle.boundingRect()).united(self.bottom_handle.boundingRect())
    
    def set_edit_mode(self, value: bool):
        if value:
            self.set_mode(StickMode.EditDelete)
        else:
            self.set_mode(StickMode.Display)
    
    def set_mode(self, mode: StickMode):
        if mode == StickMode.Display:
            self.btn_delete.setVisible(False)
            self.top_handle.setVisible(False)
            self.mid_handle.setVisible(False)
            self.bottom_handle.setVisible(False)
            self.link_button.setVisible(False)
            self.available_for_linking = False
            self.link_source = False
            self.zero_btn.setVisible(False)
            self.setVisible(self.stick.is_visible)
        elif mode == StickMode.EditDelete:
            self.set_mode(StickMode.Display)
            self.top_handle.setVisible(True)
            self.mid_handle.setVisible(True)
            self.bottom_handle.setVisible(True)
            self.available_for_linking = False
            self.link_source = False
            self.btn_delete.setVisible(True)
        elif mode == StickMode.LinkSource:
            self.set_mode(StickMode.Display)
            self.link_source = True
            self.available_for_linking = False
            self.link_button.setPos(self.boundingRect().topLeft())
            self.link_button.set_width(int(self.boundingRect().width()))
            self.link_button.set_button_height(int(self.boundingRect().height()))
            self.link_button.adjust_text_to_button()
        elif mode == StickMode.LinkTarget:
            self.set_mode(StickMode.Display)
            self.link_source = False
            self.available_for_linking = True
        elif mode == StickMode.Edit:
            self.set_mode(StickMode.EditDelete)
            self.btn_delete.setVisible(False)
        elif mode == StickMode.Measurement:
            self.zero_btn.setVisible(True)
            self.setVisible(True)

        self.mode = mode
        self.update_tooltip()
        self.update()

    def mousePressEvent(self, event: QGraphicsSceneMouseEvent):
        if self.mode != StickMode.EditDelete:
            return
        if self.hovered_handle is None:
            return

        self.hovered_handle.setBrush(self.handle_press_brush)
        if self.hovered_handle == self.mid_handle:
            self.bottom_handle.setBrush(self.handle_press_brush)
            self.bottom_handle.setPen(self.handle_press_pen)
            self.bottom_handle.setOpacity(0.5)
            self.top_handle.setBrush(self.handle_press_brush)
            self.top_handle.setPen(self.handle_press_pen)
            self.top_handle.setOpacity(0.5)
        self.hovered_handle.setPen(self.handle_press_pen)
        self.hovered_handle.setOpacity(0.5)
        self.handle_mouse_offset = self.hovered_handle.rect().center() - event.pos()
        self.btn_delete.setVisible(False)

    def mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent):
        if self.available_for_linking:
            self.link_accepted.emit(self)
            return

        if self.mode == StickMode.Measurement:
            old_snow = self.stick.snow_height_px
            self.measured_height = self.proposed_snow_height
            self.stick.set_snow_height_px(self.proposed_snow_height)
            if abs(old_snow - self.proposed_snow_height) > 0:
                self.measurement_corrected.emit(self)
            self.proposed_snow_height = -1

        if self.mode != StickMode.EditDelete and self.mode != StickMode.Edit:
            return

        if self.hovered_handle is not None:
            self.hovered_handle.setBrush(self.handle_hover_brush)
            self.hovered_handle.setPen(self.handle_idle_pen)
            self.hovered_handle.setOpacity(1.0)
            if self.hovered_handle == self.mid_handle:
                self.bottom_handle.setBrush(self.handle_idle_brush)
                self.bottom_handle.setPen(self.handle_idle_pen)
                self.bottom_handle.setOpacity(1.0)
                self.top_handle.setBrush(self.handle_idle_brush)
                self.top_handle.setPen(self.handle_idle_pen)
                self.top_handle.setOpacity(1.0)
            self.stick_changed.emit(self)
        self.hovered_handle = None
        if self.mode == StickMode.EditDelete:
            self.btn_delete.setVisible(True)
    
    def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent):
        if self.hovered_handle is None:
            return
        if self.hovered_handle == self.top_handle:
            self.line.setP1((event.pos() + self.handle_mouse_offset).toPoint())
        elif self.hovered_handle == self.bottom_handle:
            self.line.setP2((event.pos() + self.handle_mouse_offset).toPoint())
        else:
            displacement = event.pos() - event.lastPos()
            self.setPos(self.pos() + displacement)
        self.adjust_handles()
        self.adjust_stick()
        self.scene().update()

    def set_top(self, pos: QPoint):
        self.line.setP1(pos)
        self.adjust_handles()
        self.adjust_stick()
        self.scene().update()

    def set_bottom(self, pos: QPoint):
        self.line.setP2(pos)
        self.adjust_handles()
        self.adjust_stick()
        self.scene().update()

    def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent):
        if self.available_for_linking:
            self.hovered.emit(True, self)
        elif self.link_source:
            self.link_button.setVisible(True)
        self.scene().update()

    def hoverLeaveEvent(self, event: QGraphicsSceneHoverEvent):
        for h in self.handles:
            h.setBrush(self.handle_idle_brush)
        self.hovered_handle = None
        if self.available_for_linking:
            self.hovered.emit(False, self)
        self.link_button.setVisible(False)
        self.proposed_snow_height = -1
        self.scene().update()
    
    def hoverMoveEvent(self, event: QGraphicsSceneHoverEvent):
        if self.mode != StickMode.EditDelete and self.mode != StickMode.Edit and self.mode != StickMode.Measurement:
            return
        if self.mode == StickMode.Measurement:
            self.proposed_snow_height = max(self.line.p2().y() - event.pos().y(), 0)
            self.update()
            return
        hovered_handle = list(filter(lambda h: h.rect().contains(event.pos()), self.handles))
        if len(hovered_handle) == 0:
            if self.hovered_handle is not None:
                self.hovered_handle.setBrush(self.handle_idle_brush)
                self.hovered_handle = None
            return
        if self.hovered_handle is not None and self.hovered_handle != hovered_handle[0]:
            self.hovered_handle.setBrush(self.handle_idle_brush)
        self.hovered_handle = hovered_handle[0]
        if self.hovered_handle == self.top_handle:
            self.top_handle.setBrush(self.handle_hover_brush)
        elif self.hovered_handle == self.bottom_handle:
            self.bottom_handle.setBrush(self.handle_hover_brush)
        else:
            self.mid_handle.setBrush(self.handle_hover_brush)

        self.scene().update()
    
    def adjust_stick(self):
        self.stick.top[0] = self.pos().x() + self.line.p1().x()
        self.stick.top[1] = self.pos().y() + self.line.p1().y()
        self.stick.bottom[0] = self.pos().x() + self.line.p2().x()
        self.stick.bottom[1] = self.pos().y() + self.line.p2().y()

    def adjust_handles(self):
        if self.line.p1().y() > self.line.p2().y():
            p1, p2 = self.line.p1(), self.line.p2()
            self.line.setP1(p2)
            self.line.setP2(p1)
            if self.hovered_handle is not None:
                self.hovered_handle.setBrush(self.handle_idle_brush)
                self.hovered_handle.setPen(self.handle_idle_pen)
                self.hovered_handle = self.top_handle if self.hovered_handle == self.bottom_handle else self.bottom_handle
                self.hovered_handle.setBrush(self.handle_press_brush)
                self.hovered_handle.setPen(self.handle_press_pen)
        rect = self.top_handle.rect()
        rect.moveCenter(self.line.p1())
        self.top_handle.setRect(rect)
        rect = self.bottom_handle.rect()
        rect.moveCenter(self.line.p2())
        self.bottom_handle.setRect(rect)
        rect = self.mid_handle.rect()
        rect.moveCenter(self.line.center())
        self.mid_handle.setRect(rect)
        self.btn_delete.setPos(self.top_handle.rect().center() - QPointF(self.btn_delete.boundingRect().width() / 2,
                                                               self.btn_delete.boundingRect().height() + self.top_handle.boundingRect().height() / 2))

    def set_available_for_linking(self, available: bool):
        self.available_for_linking = available

    def set_is_link_source(self, is_source: bool):
        self.link_source = is_source
        self.link_button.setPos(self.boundingRect().topLeft())
        self.link_button.set_width(int(self.boundingRect().width()))
        self.link_button.set_button_height(int(self.boundingRect().height()))
        self.link_button.adjust_text_to_button()
    
    def set_frame_color(self, color: Optional[QColor]):
        self.frame_color = color if color is not None else self.normal_color
        self.update()

    def set_is_linked(self, value: bool):
        self.is_linked = value
        if not self.is_linked:
            self.set_frame_color(None)
            if self.available_for_linking:
                self.highlight(QColor(0, 255, 0, 100))
            else:
                self.highlight(None)
        self.update_tooltip()

    def adjust_line(self):
        self.setPos(QPointF(0.5 * (self.stick.top[0] + self.stick.bottom[0]), 0.5 * (self.stick.top[1] + self.stick.bottom[1])))
        vec = 0.5 * (self.stick.top - self.stick.bottom)
        self.line.setP1(QPointF(vec[0], vec[1]))
        self.line.setP2(-self.line.p1())
        self.gline.setLine(self.line)
        self.adjust_handles()
        self.stick_label_text.setPos(self.line.p1() - QPointF(0.5 * self.stick_label_text.boundingRect().width(),
                                                             1.3 * self.stick_label_text.boundingRect().height()))
        self.update()

    def set_selected(self, selected: bool):
        self.selected = selected
        self.update()

    def is_selected(self) -> bool:
        return self.selected

    def set_snow_height(self, height: int):
        self.measured_height = height
        self.update()

    def border_normal(self):
        self.current_color = self.normal_color
        self.update()

    def border_positive(self):
        self.current_color = self.positive_color
        self.update()

    def border_negative(self):
        self.current_color = self.negative_color
        self.update()

    @pyqtProperty(QColor)
    def highlight_color(self) -> QColor:
        return self.current_highlight_color

    @highlight_color.setter
    def highlight_color(self, color: QColor):
        self.current_highlight_color = color

    def highlight(self, color: Optional[QColor], animated: bool = False):
        self.highlighted = color is not None
        if not animated or color is None:
            self.highlight_animation.stop()
            self.current_highlight_color = self.normal_color if color is None else color
            self.update()
            return
        self.highlight_animation.setStartValue(color)
        self.highlight_animation.setEndValue(color)
        self.highlight_animation.setKeyValueAt(0.5, color.darker())
        self.highlight_animation.setDuration(2000)
        self.highlight_animation.setLoopCount(-1)
        self.highlight_animation.start()

    def handle_link_button_hovered(self, btn: Dict[str, Any]):
        self.link_button.setVisible(btn['hovered'])

    def handle_highlight_animation_value_changed(self, new: QColor):
        if not self.deleting:
            self.update(self.boundingRect().marginsAdded(QMarginsF(10, 10, 10, 10)))

    def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent) -> None:
        self.right_clicked.emit({'stick_widget': self})

    def set_stick_label(self, label: str):
        self.stick.label = label
        self.stick_label_text.setText(label)
        self.update_tooltip()
        self.update()

    def get_stick_label(self) -> str:
        return self.stick.label

    def get_stick_length_cm(self) -> int:
        return self.stick.length_cm

    def set_stick_length_cm(self, length: int):
        self.stick.length_cm = length
        self.update_tooltip()
        self.update()

    def update_tooltip(self):
        if self.mode != StickMode.Display or self.mode == StickMode.Measurement:
            self.setToolTip("")
            return
        snow_txt = "Snow height: "
        if self.stick.snow_height_px >= 0:
            snow_txt += str(self.stick.snow_height_cm) + " cm"
            self.stick_label_text.setText(str(self.stick.snow_height_cm))
        else:
            snow_txt = "not measured"
            self.stick_label_text.setVisible(False)
        self.stick_label_text.setText(self.stick.label)
        self.stick_label_text.setVisible(True)
        stick_view_text = ''
        role = ''
        if self.stick.alternative_view is not None:
            alt_view = self.stick.alternative_view
            role = " - primary"
            alt = "Secondary"
            if not self.stick.primary:
                role = " - secondary"
                alt = "Primary"
            stick_view_text = f'\n{alt} view: {alt_view.label} in {alt_view.camera_folder.name}\n'
        mark = '*' if self.stick.determines_quality else ''
        self.setToolTip(f'{mark}{self.stick.label}{role}{stick_view_text}\nLength: {self.stick.length_cm} cm\n{snow_txt}')

    def set_stick(self, stick: Stick):
        self.reset_d_btns()
        self.stick = stick
        self.adjust_line()
        self.adjust_handles()
        self.set_snow_height(stick.snow_height_px)
        self.update_tooltip()
        self.set_show_measurements(self.show_measurements)
        if self.mode == StickMode.Measurement:
            self.set_frame_color(QColor(200, 100, 0, 100) if not self.stick.is_visible else None)
            self.setVisible(True)
            self.clearly_visible_btn.setVisible(not self.stick.is_visible)
        else:
            self.setVisible(self.stick.is_visible)

    def set_show_measurements(self, show: bool):
        self.show_measurements = show
        if self.show_measurements:
            self.stick_label_text.setText(str(self.stick.snow_height_cm) if self.stick.snow_height_cm >= 0 else
                                          "n/a")
        else:
            self.stick_label_text.setText(self.stick.label)
        self.update()

    def handle_zero(self):
        self.measured_height = 0
        self.stick.set_snow_height_px(0)
        self.measurement_corrected.emit(self)

    def reset_d_btns(self):
        self.zero_btn.set_default_state()
Ejemplo n.º 29
0
class EdgeItem(GraphItem):

    _qt_pen_styles = {
        'dashed': Qt.DashLine,
        'dotted': Qt.DotLine,
        'solid': Qt.SolidLine,
    }

    def __init__(self,
                 highlight_level,
                 spline,
                 label_center,
                 label,
                 from_node,
                 to_node,
                 parent=None,
                 penwidth=1,
                 edge_color=None,
                 style='solid'):
        super(EdgeItem, self).__init__(highlight_level, parent)

        self.from_node = from_node
        self.from_node.add_outgoing_edge(self)
        self.to_node = to_node
        self.to_node.add_incoming_edge(self)

        self._default_edge_color = self._COLOR_BLACK
        if edge_color is not None:
            self._default_edge_color = edge_color

        self._default_text_color = self._COLOR_BLACK
        self._default_color = self._COLOR_BLACK
        self._text_brush = QBrush(self._default_color)
        self._shape_brush = QBrush(self._default_color)
        if style in ['dashed', 'dotted']:
            self._shape_brush = QBrush(Qt.transparent)
        self._label_pen = QPen()
        self._label_pen.setColor(self._default_text_color)
        self._label_pen.setJoinStyle(Qt.RoundJoin)
        self._edge_pen = QPen(self._label_pen)
        self._edge_pen.setWidth(penwidth)
        self._edge_pen.setColor(self._default_edge_color)
        self._edge_pen.setStyle(self._qt_pen_styles.get(style, Qt.SolidLine))

        self._sibling_edges = set()

        self._label = None
        if label is not None:
            self._label = QGraphicsSimpleTextItem(label)
            self._label.setFont(GraphItem._LABEL_FONT)
            label_rect = self._label.boundingRect()
            label_rect.moveCenter(label_center)
            self._label.setPos(label_rect.x(), label_rect.y())
            self._label.hoverEnterEvent = self._handle_hoverEnterEvent
            self._label.hoverLeaveEvent = self._handle_hoverLeaveEvent
            self._label.setAcceptHoverEvents(True)

        # spline specification according to
        # http://www.graphviz.org/doc/info/attrs.html#k:splineType
        coordinates = spline.split(' ')
        # extract optional end_point
        end_point = None
        if (coordinates[0].startswith('e,')):
            parts = coordinates.pop(0)[2:].split(',')
            end_point = QPointF(float(parts[0]), -float(parts[1]))
        # extract optional start_point
        if (coordinates[0].startswith('s,')):
            parts = coordinates.pop(0).split(',')

        # first point
        parts = coordinates.pop(0).split(',')
        point = QPointF(float(parts[0]), -float(parts[1]))
        path = QPainterPath(point)

        while len(coordinates) > 2:
            # extract triple of points for a cubic spline
            parts = coordinates.pop(0).split(',')
            point1 = QPointF(float(parts[0]), -float(parts[1]))
            parts = coordinates.pop(0).split(',')
            point2 = QPointF(float(parts[0]), -float(parts[1]))
            parts = coordinates.pop(0).split(',')
            point3 = QPointF(float(parts[0]), -float(parts[1]))
            path.cubicTo(point1, point2, point3)

        self._arrow = None
        if end_point is not None:
            # draw arrow
            self._arrow = QGraphicsPolygonItem()
            polygon = QPolygonF()
            polygon.append(point3)
            offset = QPointF(end_point - point3)
            corner1 = QPointF(-offset.y(), offset.x()) * 0.35
            corner2 = QPointF(offset.y(), -offset.x()) * 0.35
            polygon.append(point3 + corner1)
            polygon.append(end_point)
            polygon.append(point3 + corner2)
            self._arrow.setPolygon(polygon)
            self._arrow.hoverEnterEvent = self._handle_hoverEnterEvent
            self._arrow.hoverLeaveEvent = self._handle_hoverLeaveEvent
            self._arrow.setAcceptHoverEvents(True)

        self._path = QGraphicsPathItem(parent)
        self._path.setPath(path)
        self.addToGroup(self._path)

        self.set_node_color()
        self.set_label_color()

    def add_to_scene(self, scene):
        scene.addItem(self)
        if self._label is not None:
            scene.addItem(self._label)
        if self._arrow is not None:
            scene.addItem(self._arrow)

    def setToolTip(self, tool_tip):
        super(EdgeItem, self).setToolTip(tool_tip)
        if self._label is not None:
            self._label.setToolTip(tool_tip)
        if self._arrow is not None:
            self._arrow.setToolTip(tool_tip)

    def add_sibling_edge(self, edge):
        self._sibling_edges.add(edge)

    def set_node_color(self, color=None):
        if color is None:
            self._label_pen.setColor(self._default_text_color)
            self._text_brush.setColor(self._default_color)
            if self._shape_brush.isOpaque():
                self._shape_brush.setColor(self._default_edge_color)
            self._edge_pen.setColor(self._default_edge_color)
        else:
            self._label_pen.setColor(color)
            self._text_brush.setColor(color)
            if self._shape_brush.isOpaque():
                self._shape_brush.setColor(color)
            self._edge_pen.setColor(color)

        self._path.setPen(self._edge_pen)
        if self._arrow is not None:
            self._arrow.setBrush(self._shape_brush)
            self._arrow.setPen(self._edge_pen)

    def set_label_color(self, color=None):
        if color is None:
            self._label_pen.setColor(self._default_text_color)
        else:
            self._label_pen.setColor(color)

        if self._label is not None:
            self._label.setBrush(self._text_brush)
            self._label.setPen(self._label_pen)

    def _handle_hoverEnterEvent(self, event):
        # hovered edge item in red
        self.set_node_color(self._COLOR_RED)
        self.set_label_color(self._COLOR_RED)

        if self._highlight_level > 1:
            if self.from_node != self.to_node:
                # from-node in blue
                self.from_node.set_node_color(self._COLOR_BLUE)
                # to-node in green
                self.to_node.set_node_color(self._COLOR_GREEN)
            else:
                # from-node/in-node in teal
                self.from_node.set_node_color(self._COLOR_TEAL)
                self.to_node.set_node_color(self._COLOR_TEAL)
        if self._highlight_level > 2:
            # sibling edges in orange
            for sibling_edge in self._sibling_edges:
                sibling_edge.set_node_color(self._COLOR_ORANGE)

    def _handle_hoverLeaveEvent(self, event):
        self.set_node_color()
        self.set_label_color()
        if self._highlight_level > 1:
            self.from_node.set_node_color()
            self.to_node.set_node_color()
        if self._highlight_level > 2:
            for sibling_edge in self._sibling_edges:
                sibling_edge.set_node_color()
Ejemplo n.º 30
0
class Scene(QGraphicsScene):
    def __init__(self, parent=None):
        QGraphicsScene.__init__(self, parent)

        # set pritisnutih tastera
        self.keys_pressed = set()

        # pozadina
        self.bg = QGraphicsRectItem()
        self.bg.setRect(-1, -1, SCREEN_WIDTH + 2, SCREEN_HEIGHT + 2)
        self.bg.setBrush(QBrush(Qt.black))
        self.addItem(self.bg)

        # brojaci za pomeranje protivnika
        self.left = 1
        self.right = 5

        # lista protivnika
        self.enemies = []
        # nasumicni indeks protivnika koji puca
        self.randomEnemyIndex = randint(0, len(self.enemies))
        # nasumicna lista indeksa protivnika koji ce imati specijalnu moc
        self.enemyPowerUps = []

        # pravljenje i iscrtavanje protivnika
        self.threadFinished = False
        _thread.start_new_thread(self.draw_enemies, ())
        while not self.threadFinished:
            continue
        self.threadFinished = False

        # igrac 1 (plavi)
        self.player1 = Player1()
        self.player1.setPos(20, 530)
        self.addItem(self.player1)

        # igrac 2 (crveni)
        self.player2 = Player2()
        self.player2.setPos(589, 530)
        self.addItem(self.player2)

        # metak igraca 1 (plavi)
        self.bullet1 = Bullet1(PLAYER_BULLET_X_OFFSETS, PLAYER_BULLET_Y)
        self.bullet1.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
        self.addItem(self.bullet1)

        # metak igraca 2 (crveni)
        self.bullet2 = Bullet2(PLAYER_BULLET_X_OFFSETS, PLAYER_BULLET_Y)
        self.bullet2.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
        self.addItem(self.bullet2)

        # pobednik
        self.winner = 0

        # power up i power down igraca 1 (plavi)
        self.player1PowerUp = QGraphicsPixmapItem()
        self.player1PowerUp.setPixmap(QPixmap("Images/powerUp.png"))
        self.player1PowerDown = QGraphicsPixmapItem()
        self.player1PowerDown.setPixmap(QPixmap("Images/powerDown.png"))

        # power up i power down igraca 2 (crveni)
        self.player2PowerUp = QGraphicsPixmapItem()
        self.player2PowerUp.setPixmap(QPixmap("Images/powerUp.png"))
        self.player2PowerDown = QGraphicsPixmapItem()
        self.player2PowerDown.setPixmap(QPixmap("Images/powerDown.png"))

        # protivnicki metak (narandzasti)
        self.bulletEnemy = BulletEnemy(ENEMY_BULLET_X_OFFSET,
                                       ENEMY_BULLET_Y_OFFSET)
        self.bulletEnemy.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
        self.addItem(self.bulletEnemy)

        # polje za rezultate
        self.scoreField = QGraphicsRectItem()
        self.scoreField.setRect(672, -1, 128, SCREEN_HEIGHT + 2)
        self.scoreField.setBrush(QBrush(Qt.darkGray))
        self.addItem(self.scoreField)

        # trenutni nivo
        self.level = 1

        # iscrtavanje trenutnog nivoa
        self.levelFont = QFont()
        self.levelFont.setPixelSize(25)
        self.levelFont.setBold(1)
        self.levelField = QGraphicsSimpleTextItem("Level: " + str(self.level))
        self.levelField.setBrush(QBrush(Qt.green))
        self.levelField.setPos(677, 20)
        self.levelField.setFont(self.levelFont)
        self.addItem(self.levelField)

        self.playerFont = QFont()
        self.playerFont.setPixelSize(20)
        self.playerFont.setBold(1)

        # iscrtavanje broja zivota igraca 1
        self.player1Lives = QGraphicsSimpleTextItem("Player 1: ")
        self.player1Lives.setBrush(QBrush(Qt.blue))
        self.player1Lives.setPos(674, 130)
        self.player1Lives.setFont(self.playerFont)
        self.addItem(self.player1Lives)
        self.livesPlayer1 = [
            LifePlayer1(680, 175),
            LifePlayer1(720, 175),
            LifePlayer1(760, 175)
        ]
        for l in self.livesPlayer1:
            self.addItem(l)

        # iscrtavanje broja zivota igraca 2
        self.player2Lives = QGraphicsSimpleTextItem("Player 2: ")
        self.player2Lives.setBrush(QBrush(Qt.blue))
        self.player2Lives.setPos(674, 330)
        self.player2Lives.setFont(self.playerFont)
        self.addItem(self.player2Lives)
        self.livesPlayer2 = [
            LifePlayer2(680, 375),
            LifePlayer2(720, 375),
            LifePlayer2(760, 375)
        ]
        for l in self.livesPlayer2:
            self.addItem(l)

        self.scoreFont = QFont()
        self.scoreFont.setPixelSize(20)
        self.scoreFont.setBold(1)

        # iscrtavanje rezultata igraca 1
        self.player1Score = 0
        self.player1Scores = QGraphicsSimpleTextItem("Score: \n" +
                                                     str(self.player1Score))
        self.player1Scores.setBrush(QBrush(Qt.blue))
        self.player1Scores.setPos(674, 220)
        self.player1Scores.setFont(self.scoreFont)
        self.addItem(self.player1Scores)

        # iscrtavanje rezultata igraca 1
        self.player2Score = 0
        self.player2Scores = QGraphicsSimpleTextItem("Score: \n" +
                                                     str(self.player2Score))
        self.player2Scores.setBrush(QBrush(Qt.blue))
        self.player2Scores.setPos(674, 420)
        self.player2Scores.setFont(self.scoreFont)
        self.addItem(self.player2Scores)

        # tajmer za iscrtavanje slike 60 puta u sekndi (60 fps)
        self.timer = QBasicTimer()
        self.timer.start(16, self)

        # tajmer za pomeranje neprijatelja
        self.timerEnemy = QTimer()
        self.timerEnemy.timeout.connect(self.game_update_enemy)
        self.timerEnemy.start(1000)

        # icrtavanje scene
        self.view = QGraphicsView(self)
        self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.show()
        self.view.setFixedSize(SCREEN_WIDTH, SCREEN_HEIGHT)
        self.setSceneRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)
        self.view.setGeometry(560, 240, 0, 0)

    def keyPressEvent(self, event):
        self.keys_pressed.add(event.key())

    def keyReleaseEvent(self, event):
        self.keys_pressed.remove(event.key())

    def timerEvent(self, event):
        self.game_update()
        self.update()

    def game_update(self):
        self.player1.game_update(self.keys_pressed)
        self.player2.game_update(self.keys_pressed)

        for e in self.enemies:
            # ako je neprijatelj zavrsio sa padanjem, brisemo ga
            if e.frames == -1:
                self.removeItem(e)
                self.enemies.remove(e)
                continue
            # ako je neprijatelj izabran za padanje, nastavlja da pada
            if e.chosen:
                e.collapse()

            # igrac 1 pogodio neprijatelja
            if e.x() <= self.bullet1.x() <= e.x() + 32:
                if e.y() <= self.bullet1.y() <= e.y() + 26:
                    if e.powerUp:
                        temp = randint(0, 3)
                        if temp == 0:
                            if self.player1.speed == 2:
                                self.removeItem(self.player1PowerDown)
                            self.player1.speed = 8
                            self.player1PowerUp.setPos(770, 130)
                            self.addItem(self.player1PowerUp)
                        elif temp == 1:
                            if self.player1.speed == 8:
                                self.removeItem(self.player1PowerUp)
                            self.player1.speed = 2
                            self.player1PowerDown.setPos(770, 130)
                            self.addItem(self.player1PowerDown)
                        elif temp == 2:
                            if self.player1.lives == 3:
                                pass
                            elif self.player1.lives == 2:
                                self.livesPlayer1.append(LifePlayer1(760, 175))
                                self.player1.lives += 1
                                self.addItem(self.livesPlayer1[-1])
                            elif self.player1.lives == 1:
                                self.livesPlayer1.append(LifePlayer1(720, 175))
                                self.player1.lives += 1
                                self.addItem((self.livesPlayer1[-1]))
                            else:
                                pass
                        else:
                            self.player1Score += 100
                            self.player1Scores.setText("Score: \n" +
                                                       str(self.player1Score))
                    self.removeItem(e)
                    self.enemies.remove(e)
                    self.removeItem(self.bullet1)
                    self.bullet1.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
                    self.addItem(self.bullet1)
                    self.player1Score += 10
                    self.player1Scores.setText("Score: \n" +
                                               str(self.player1Score))
                    continue

            # igrac 2 pogodio neprijatelja
            if e.x() <= self.bullet2.x() <= e.x() + 32:
                if e.y() <= self.bullet2.y() <= e.y() + 26:
                    if e.powerUp:
                        temp = randint(0, 3)
                        if temp == 0:
                            if self.player2.speed == 2:
                                self.removeItem(self.player2PowerDown)
                            self.player2.speed = 8
                            self.player2PowerUp.setPos(770, 330)
                            self.addItem(self.player2PowerUp)
                        elif temp == 1:
                            if self.player2.speed == 8:
                                self.removeItem(self.player2PowerUp)
                            self.player2.speed = 2
                            self.player2PowerDown.setPos(770, 330)
                            self.addItem(self.player2PowerDown)
                        elif temp == 2:
                            if self.player2.lives == 3:
                                pass
                            elif self.player2.lives == 2:
                                self.livesPlayer2.append(LifePlayer2(760, 375))
                                self.player2.lives += 1
                                self.addItem(self.livesPlayer2[-1])
                            elif self.player2.lives == 1:
                                self.livesPlayer2.append(LifePlayer2(720, 375))
                                self.player2.lives += 1
                                self.addItem((self.livesPlayer2[-1]))
                            else:
                                pass
                        else:
                            self.player2Score += 100
                            self.player2Scores.setText("Score: \n" +
                                                       str(self.player2Score))
                    self.removeItem(e)
                    self.enemies.remove(e)
                    self.removeItem(self.bullet2)
                    self.bullet2.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
                    self.addItem(self.bullet2)
                    self.player2Score += 10
                    self.player2Scores.setText("Score: \n" +
                                               str(self.player2Score))
                    continue

            # na igraca 1 se obrusio neprijatelj
            if self.player1.y() <= e.y() + 26 <= self.player1.y() + 53:
                if self.player1.x() <= e.x(
                ) <= self.player1.x() + 69 or self.player1.x(
                ) <= e.x() + 32 <= self.player1.x() + 69:
                    if self.player1.lives > 0:
                        if self.player1.speed == 8:
                            self.removeItem(self.player1PowerUp)
                        elif self.player1.speed == 2:
                            self.removeItem(self.player1PowerDown)
                        self.player1.speed = 4
                        e.frames = -1
                        self.player1.lives -= 1
                        self.removeItem(self.livesPlayer1[-1])
                        self.livesPlayer1.remove(self.livesPlayer1[-1])
                        self.player1.setPos(20, 530)
                        if self.player1.lives <= 0:
                            self.removeItem(self.player1)
                            if self.player1.speed == 8:
                                self.removeItem(self.player1PowerUp)
                            elif self.player1.speed == 2:
                                self.removeItem(self.player1PowerDown)
                            if self.player2.lives > 0:
                                self.winner = 2

            # na igraca 2 se obrusio neprijatelj
            if self.player2.y() <= e.y() + 26 <= self.player2.y() + 53:
                if self.player2.x() <= e.x(
                ) <= self.player2.x() + 69 or self.player2.x(
                ) <= e.x() + 32 <= self.player2.x() + 69:
                    if self.player2.lives > 0:
                        if self.player2.speed == 8:
                            self.removeItem(self.player1PowerUp)
                        elif self.player2.speed == 2:
                            self.removeItem(self.player2PowerDown)
                        self.player2.speed = 4
                        e.frames = -1
                        self.player2.lives -= 1
                        self.removeItem(self.livesPlayer2[-1])
                        self.livesPlayer2.remove(self.livesPlayer2[-1])
                        self.player2.setPos(589, 530)
                        if self.player2.lives <= 0:
                            self.removeItem(self.player2)
                            if self.player2.speed == 8:
                                self.removeItem(self.player2PowerUp)
                            elif self.player2.speed == 2:
                                self.removeItem(self.player2PowerDown)
                            if self.player1.lives > 0:
                                self.winner = 1

        # igraca 1 pogodio laser neprijatelja
        if self.player1.x() + 69 >= self.bulletEnemy.x() >= self.player1.x():
            if self.player1.y() + 53 >= self.bulletEnemy.y() >= self.player1.y(
            ):
                if self.player1.lives > 0:
                    if self.player1.speed == 8:
                        self.removeItem(self.player1PowerUp)
                    elif self.player1.speed == 2:
                        self.removeItem(self.player1PowerDown)
                    self.player1.speed = 4
                    self.bulletEnemy.active = False
                    self.player1.lives -= 1
                    self.removeItem(self.livesPlayer1[-1])
                    self.livesPlayer1.remove(self.livesPlayer1[-1])
                    self.player1.setPos(20, 530)
                    if self.player1.lives <= 0:
                        self.removeItem(self.player1)
                        if self.player2.lives > 0:
                            self.winner = 2

        # igraca 2 pogodio laser neprijatelja
        if self.player2.x() + 69 >= self.bulletEnemy.x() >= self.player2.x():
            if self.player2.y() + 53 >= self.bulletEnemy.y() >= self.player2.y(
            ):
                if self.player2.lives > 0:
                    if self.player2.speed == 8:
                        self.removeItem(self.player2PowerUp)
                    elif self.player2.speed == 2:
                        self.removeItem(self.player2PowerDown)
                    self.player2.speed = 4
                    self.bulletEnemy.active = False
                    self.player2.lives -= 1
                    self.removeItem(self.livesPlayer2[-1])
                    self.livesPlayer2.remove(self.livesPlayer2[-1])
                    self.player2.setPos(589, 530)
                    if self.player2.lives <= 0:
                        self.removeItem(self.player2)
                        if self.player1.lives > 0:
                            self.winner = 1

        # pomeranje metaka
        self.bullet1.game_update(self.keys_pressed, self.player1)
        self.bullet2.game_update(self.keys_pressed, self.player2)
        try:
            self.bulletEnemy.game_update(self.enemies[self.randomEnemyIndex])
            if not self.bulletEnemy.active:
                self.randomEnemyIndex = randint(0, len(self.enemies))
        except:
            self.randomEnemyIndex = randint(0, len(self.enemies))

        # nasumicno biranje obrusavanja
        try:
            if randint(0, 500) == 0:
                self.enemies[randint(0, len(self.enemies))].chosen = True
        except:
            pass

        # kraj igre
        if self.player1.lives == 0 and self.player2.lives == 0:
            self.timer.stop()
            self.timerEnemy.stop()
            self.removeItem(self.bg)
            self.bg.setPos(-128, 0)
            self.addItem(self.bg)
            fontWinner = QFont()
            fontWinner.setPixelSize(40)
            textWinner = QGraphicsSimpleTextItem()
            textWinner.setFont(fontWinner)
            if self.winner == 1:
                textWinner.setText("WINNER PLAYER 1")
                textWinner.setBrush(QBrush(Qt.blue))
                self.player1.setPos(310, 300)
                self.addItem(self.player1)
            elif self.winner == 2:
                textWinner.setText("WINNER PLAYER 2")
                textWinner.setBrush(QBrush(Qt.red))
                self.player2.setPos(310, 300)
                self.addItem(self.player2)
            textWinner.setPos(180, 200)
            self.addItem(textWinner)

        # pobedjen nivo
        if len(self.enemies) == 0:
            self.timer.stop()
            self.timerEnemy.stop()
            if self.player1.lives > 0:
                self.removeItem(self.player1)
                self.removeItem(self.bullet1)
            if self.player2.lives > 0:
                self.removeItem(self.player2)
                self.removeItem(self.bullet2)
            self.removeItem(self.bulletEnemy)
            self.new_level()

    # pomeranje neprijatelja
    def game_update_enemy(self):
        if 0 < self.right < 9:
            self.right += 1
            if self.right == 9:
                self.right = 0
                self.left = 1
            for e in self.enemies:
                e.move_right()
        elif 0 < self.left < 9:
            self.left += 1
            if self.left == 9:
                self.left = 0
                self.right = 1
            for e in self.enemies:
                e.move_left()

    # pravljenje novog nivoa
    def new_level(self):
        self.level += 1
        self.levelField.setText("Level: " + str(self.level))

        self.left = 1
        self.right = 5

        self.threadFinished = False
        _thread.start_new_thread(self.draw_enemies, ())
        while not self.threadFinished:
            continue
        self.threadFinished = False

        for e in self.enemies:
            e.collapseSpeed += self.level
            e.collapseFrames = 700 / e.collapseSpeed

        if self.player1.lives > 0:
            self.player1.setPos(20, 530)
            self.bullet1 = Bullet1(PLAYER_BULLET_X_OFFSETS, PLAYER_BULLET_Y)
            self.bullet1.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
            self.addItem(self.bullet1)
            self.addItem(self.player1)
        if self.player2.lives > 0:
            self.player2.setPos(589, 530)
            self.bullet2 = Bullet2(PLAYER_BULLET_X_OFFSETS, PLAYER_BULLET_Y)
            self.bullet2.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
            self.addItem(self.bullet2)
            self.addItem(self.player2)

        self.bulletEnemy = BulletEnemy(ENEMY_BULLET_X_OFFSET,
                                       ENEMY_BULLET_Y_OFFSET)
        self.bulletEnemy.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
        self.bulletEnemy.speed += self.level
        self.bulletEnemy.frames = 700 / self.bulletEnemy.speed
        self.addItem(self.bulletEnemy)

        self.timer.start(16, self)
        self.timerEnemy.start(1000)

    def draw_enemies(self):
        self.threadFinished = False
        self.enemies = [
            Enemy(131, 10),
            Enemy(173, 10),
            Enemy(215, 10),
            Enemy(257, 10),
            Enemy(299, 10),
            Enemy(341, 10),
            Enemy(383, 10),
            Enemy(425, 10),
            Enemy(467, 10),
            Enemy(509, 10),
            Enemy(131, 50),
            Enemy(173, 50),
            Enemy(215, 50),
            Enemy(257, 50),
            Enemy(299, 50),
            Enemy(341, 50),
            Enemy(383, 50),
            Enemy(425, 50),
            Enemy(467, 50),
            Enemy(509, 50),
            Enemy(131, 90),
            Enemy(173, 90),
            Enemy(215, 90),
            Enemy(257, 90),
            Enemy(299, 90),
            Enemy(341, 90),
            Enemy(383, 90),
            Enemy(425, 90),
            Enemy(467, 90),
            Enemy(509, 90)
        ]

        pool = multiprocessing.Pool(processes=1)
        result = pool.apply_async(get_enemy_power_ups,
                                  (len(self.enemies) - 1, 5))
        self.enemyPowerUps = result.get(timeout=1)
        pool.close()

        for i in self.enemyPowerUps:
            self.enemies[i].setPixmap(QPixmap("Images/enemyPowerUp.png"))
            self.enemies[i].powerUp = True

        for e in self.enemies:
            self.addItem(e)

        self.randomEnemyIndex = randint(0, len(self.enemies))

        self.threadFinished = True
Ejemplo n.º 31
0
class CameraView(QGraphicsObject):

    font: QFont = QFont("monospace", 16)
    stick_link_requested = pyqtSignal(StickWidget)
    stick_context_menu = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject')
    stick_widgets_out_of_sync = pyqtSignal('PyQt_PyObject')
    visibility_toggled = pyqtSignal()
    synchronize_clicked = pyqtSignal('PyQt_PyObject')
    previous_photo_clicked = pyqtSignal('PyQt_PyObject')
    next_photo_clicked = pyqtSignal('PyQt_PyObject')
    sync_confirm_clicked = pyqtSignal('PyQt_PyObject')
    sync_cancel_clicked = pyqtSignal('PyQt_PyObject')
    first_photo_clicked = pyqtSignal('PyQt_PyObject')
    enter_pressed = pyqtSignal()

    def __init__(self, scale: float, parent: Optional[QGraphicsItem] = None):
        QGraphicsObject.__init__(self, parent)
        self.current_highlight_color = QColor(0, 0, 0, 0)
        self.current_timer = -1
        self.scaling = scale
        self.pixmap = QGraphicsPixmapItem(self)
        self.stick_widgets: List[StickWidget] = []
        self.link_cam_text = QGraphicsSimpleTextItem("Link camera...", self)
        self.link_cam_text.setZValue(40)
        self.link_cam_text.setVisible(False)
        self.link_cam_text.setFont(CameraView.font)
        self.link_cam_text.setPos(0, 0)
        self.link_cam_text.setPen(QPen(QColor(255, 255, 255, 255)))
        self.link_cam_text.setBrush(QBrush(QColor(255, 255, 255, 255)))

        self.show_add_buttons = False
        self.camera = None

        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.show_stick_widgets = False
        self.setAcceptHoverEvents(True)
        self.stick_edit_mode = False

        self.original_pixmap = self.pixmap.pixmap()

        self.hovered = False

        self.mode = 0  # TODO make enum Mode
        self.click_handler = None
        self.double_click_handler: Callable[[int, int], None] = None

        self.stick_widget_mode = StickMode.Display

        self.highlight_animation = QPropertyAnimation(self, b"highlight_color")
        self.highlight_animation.setEasingCurve(QEasingCurve.Linear)
        self.highlight_animation.valueChanged.connect(
            self.handle_highlight_color_changed)
        self.highlight_rect = QGraphicsRectItem(self)
        self.highlight_rect.setZValue(4)
        self.highlight_rect.setPen(QPen(QColor(0, 0, 0, 0)))
        self.title_btn = Button('btn_title', '', parent=self)
        self.title_btn.setFlag(QGraphicsItem.ItemIgnoresTransformations, False)
        self.title_btn.setZValue(5)
        self.title_btn.setVisible(False)

        self.sticks_without_width: List[Stick] = []
        self.current_image_name: str = ''
        self.control_widget = ControlWidget(parent=self)
        self.control_widget.setFlag(QGraphicsItem.ItemIgnoresTransformations,
                                    False)
        self.control_widget.setVisible(True)
        self._connect_control_buttons()
        self.image_available = True
        self.blur_eff = QGraphicsBlurEffect()
        self.blur_eff.setBlurRadius(5.0)
        self.blur_eff.setEnabled(False)
        self.pixmap.setGraphicsEffect(self.blur_eff)
        self.overlay_message = QGraphicsSimpleTextItem('not available',
                                                       parent=self)
        font = self.title_btn.font
        font.setPointSize(48)
        self.overlay_message.setFont(font)
        self.overlay_message.setBrush(QBrush(QColor(200, 200, 200, 200)))
        self.overlay_message.setPen(QPen(QColor(0, 0, 0, 200), 2.0))
        self.overlay_message.setVisible(False)
        self.overlay_message.setZValue(6)

        self.stick_box = QGraphicsRectItem(parent=self)
        self.stick_box.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.stick_box.setVisible(False)
        self.stick_box_start_pos = QPoint()

    def _connect_control_buttons(self):
        self.control_widget.synchronize_btn.clicked.connect(
            lambda: self.synchronize_clicked.emit(self))
        self.control_widget.prev_photo_btn.clicked.connect(
            lambda: self.previous_photo_clicked.emit(self))
        self.control_widget.next_photo_btn.clicked.connect(
            lambda: self.next_photo_clicked.emit(self))
        self.control_widget.accept_btn.clicked.connect(
            lambda: self.sync_confirm_clicked.emit(self))
        self.control_widget.cancel_btn.clicked.connect(
            lambda: self.sync_cancel_clicked.emit(self))
        self.control_widget.first_photo_btn.clicked.connect(
            lambda: self.first_photo_clicked.emit(self))

    def paint(self, painter: QPainter,
              option: PyQt5.QtWidgets.QStyleOptionGraphicsItem,
              widget: QWidget):
        if self.pixmap.pixmap().isNull():
            return
        painter.setRenderHint(QPainter.Antialiasing, True)

        if self.show_stick_widgets:
            brush = QBrush(QColor(255, 255, 255, 100))
            painter.fillRect(self.boundingRect(), brush)

        if self.mode and self.hovered:
            pen = QPen(QColor(0, 125, 200, 255))
            pen.setWidth(4)
            painter.setPen(pen)

    def boundingRect(self) -> PyQt5.QtCore.QRectF:
        return self.pixmap.boundingRect().united(
            self.title_btn.boundingRect().translated(self.title_btn.pos()))

    def initialise_with(self, camera: Camera):
        if self.camera is not None:
            self.camera.stick_added.disconnect(self.handle_stick_created)
            self.camera.sticks_added.disconnect(self.handle_sticks_added)
            self.camera.stick_removed.disconnect(self.handle_stick_removed)
            self.camera.sticks_removed.disconnect(self.handle_sticks_removed)
            self.camera.stick_changed.disconnect(self.handle_stick_changed)
        self.camera = camera
        self.prepareGeometryChange()
        self.set_image(camera.rep_image, Path(camera.rep_image_path).name)
        self.title_btn.set_label(self.camera.folder.name)
        self.title_btn.set_height(46)
        self.title_btn.fit_to_contents()
        self.title_btn.set_width(int(self.boundingRect().width()))
        self.title_btn.setPos(0, self.boundingRect().height())
        self.control_widget.title_btn.set_label(self.camera.folder.name)
        self.camera.stick_added.connect(self.handle_stick_created)
        self.camera.sticks_added.connect(self.handle_sticks_added)
        self.camera.stick_removed.connect(self.handle_stick_removed)
        self.camera.sticks_removed.connect(self.handle_sticks_removed)
        self.camera.stick_changed.connect(self.handle_stick_changed)

        self.control_widget.set_font_height(32)
        self.control_widget.set_widget_height(
            self.title_btn.boundingRect().height())
        self.control_widget.set_widget_width(int(self.boundingRect().width()))
        self.control_widget.setPos(0,
                                   self.pixmap.boundingRect().height()
                                   )  #self.boundingRect().height())
        self.control_widget.set_mode('view')
        self.update_stick_widgets()

    def set_image(self,
                  img: Optional[np.ndarray] = None,
                  image_name: Optional[str] = None):
        if img is None:
            self.show_overlay_message('not available')
            return
        self.show_overlay_message(None)
        self.prepareGeometryChange()
        barray = QByteArray(img.tobytes())
        image = QImage(barray, img.shape[1], img.shape[0],
                       QImage.Format_BGR888)
        self.original_pixmap = QPixmap.fromImage(image)
        self.pixmap.setPixmap(self.original_pixmap)
        self.highlight_rect.setRect(self.boundingRect())
        self.current_image_name = image_name

    def update_stick_widgets(self):
        stick_length = 60
        for stick in self.camera.sticks:
            sw = StickWidget(stick, self.camera, self)
            sw.set_mode(self.stick_widget_mode)
            self.connect_stick_widget_signals(sw)
            self.stick_widgets.append(sw)
            stick_length = stick.length_cm
        self.update_stick_box()
        self.scene().update()

    def scale_item(self, factor: float):
        self.prepareGeometryChange()
        pixmap = self.original_pixmap.scaledToHeight(
            int(self.original_pixmap.height() * factor))
        self.pixmap.setPixmap(pixmap)
        self.__update_title()

    def set_show_stick_widgets(self, value: bool):
        for sw in self.stick_widgets:
            sw.setVisible(value)
        self.scene().update()

    def hoverEnterEvent(self, e: QGraphicsSceneHoverEvent):
        self.hovered = True
        self.scene().update(self.sceneBoundingRect())

    def hoverLeaveEvent(self, e: QGraphicsSceneHoverEvent):
        self.hovered = False
        self.scene().update(self.sceneBoundingRect())

    def mousePressEvent(self, e: QGraphicsSceneMouseEvent):
        super().mousePressEvent(e)

    def mouseReleaseEvent(self, e: QGraphicsSceneMouseEvent):
        if self.mode == 1:
            self.click_handler(self.camera)

    def mouseDoubleClickEvent(self, event: QGraphicsSceneMouseEvent):
        if self.stick_widget_mode == StickMode.EditDelete:
            x = event.pos().toPoint().x()
            y = event.pos().toPoint().y()
            stick = self.camera.create_new_sticks(
                [(np.array([[x, y - 50], [x, y + 50]]), 3)],
                self.current_image_name)[
                    0]  #self.dataset.create_new_stick(self.camera)
            self.sticks_without_width.append(stick)

    def set_button_mode(self, click_handler: Callable[[Camera], None],
                        data: str):
        self.mode = 1  # TODO make a proper ENUM
        self.click_handler = lambda c: click_handler(c, data)

    def set_display_mode(self):
        self.mode = 0  # TODO make a proper ENUM
        self.click_handler = None

    def _remove_stick_widgets(self):
        for sw in self.stick_widgets:
            sw.setParentItem(None)
            self.scene().removeItem(sw)
            sw.deleteLater()
        self.stick_widgets.clear()

    def handle_stick_created(self, stick: Stick):
        if stick.camera_id != self.camera.id:
            return
        sw = StickWidget(stick, self.camera, self)
        sw.set_mode(self.stick_widget_mode)
        self.connect_stick_widget_signals(sw)
        self.stick_widgets.append(sw)
        self.stick_widgets_out_of_sync.emit(self)
        self.update()

    def handle_stick_removed(self, stick: Stick):
        if stick.camera_id != self.camera.id:
            return
        stick_widget = next(
            filter(lambda sw: sw.stick.id == stick.id, self.stick_widgets))
        self.disconnect_stick_widget_signals(stick_widget)
        self.stick_widgets.remove(stick_widget)
        stick_widget.setParentItem(None)
        self.scene().removeItem(stick_widget)
        stick_widget.deleteLater()
        self.update()

    def handle_sticks_removed(self, sticks: List[Stick]):
        if sticks[0].camera_id != self.camera.id:
            return
        for stick in sticks:
            to_remove: StickWidget = None
            for sw in self.stick_widgets:
                if sw.stick.id == stick.id:
                    to_remove = sw
                    break
            self.stick_widgets.remove(to_remove)
            to_remove.setParentItem(None)
            if self.scene() is not None:
                self.scene().removeItem(to_remove)
            to_remove.deleteLater()
        self.update()

    def handle_sticks_added(self, sticks: List[Stick]):
        if len(sticks) == 0:
            return
        if sticks[0].camera_id != self.camera.id:
            return
        for stick in sticks:
            sw = StickWidget(stick, self.camera, self)
            sw.set_mode(self.stick_widget_mode)
            self.connect_stick_widget_signals(sw)
            self.stick_widgets.append(sw)
        self.update_stick_box()
        self.stick_widgets_out_of_sync.emit(self)
        self.update()

    def connect_stick_widget_signals(self, stick_widget: StickWidget):
        stick_widget.delete_clicked.connect(
            self.handle_stick_widget_delete_clicked)
        stick_widget.stick_changed.connect(self.handle_stick_widget_changed)
        stick_widget.link_initiated.connect(self.handle_stick_link_initiated)
        stick_widget.right_clicked.connect(
            self.handle_stick_widget_context_menu)

    def disconnect_stick_widget_signals(self, stick_widget: StickWidget):
        stick_widget.delete_clicked.disconnect(
            self.handle_stick_widget_delete_clicked)
        stick_widget.stick_changed.disconnect(self.handle_stick_widget_changed)
        stick_widget.link_initiated.disconnect(
            self.handle_stick_link_initiated)
        stick_widget.right_clicked.disconnect(
            self.handle_stick_widget_context_menu)

    def handle_stick_widget_delete_clicked(self, stick: Stick):
        self.camera.remove_stick(stick)

    def set_stick_widgets_mode(self, mode: StickMode):
        self.stick_widget_mode = mode
        for sw in self.stick_widgets:
            sw.set_mode(mode)
        self.set_stick_edit_mode(mode == StickMode.Edit)

    def handle_stick_widget_changed(self, stick_widget: StickWidget):
        self.camera.stick_changed.emit(stick_widget.stick)

    def handle_stick_changed(self, stick: Stick):
        if stick.camera_id != self.camera.id:
            return
        sw = next(
            filter(lambda _sw: _sw.stick.id == stick.id, self.stick_widgets))
        sw.adjust_line()
        sw.update_tooltip()

    def handle_stick_link_initiated(self, stick_widget: StickWidget):
        self.stick_link_requested.emit(stick_widget)

    def get_top_left(self) -> QPointF:
        return self.sceneBoundingRect().topLeft()

    def get_top_right(self) -> QPointF:
        return self.sceneBoundingRect().topRight()

    def highlight(self, color: Optional[QColor]):
        if color is None:
            self.highlight_animation.stop()
            self.highlight_rect.setVisible(False)
            return
        alpha = color.alpha()
        color.setAlpha(0)
        self.highlight_animation.setStartValue(color)
        self.highlight_animation.setEndValue(color)
        color.setAlpha(alpha)
        self.highlight_animation.setKeyValueAt(0.5, color)
        self.highlight_animation.setDuration(2000)
        self.highlight_animation.setLoopCount(-1)
        self.highlight_rect.setPen(QPen(color))
        self.highlight_rect.setVisible(True)
        self.highlight_animation.start()

    @pyqtProperty(QColor)
    def highlight_color(self) -> QColor:
        return self.current_highlight_color

    @highlight_color.setter
    def highlight_color(self, color: QColor):
        self.current_highlight_color = color

    def handle_highlight_color_changed(self, color: QColor):
        self.highlight_rect.setBrush(QBrush(color))
        self.update()

    def handle_stick_widget_context_menu(self, sender: Dict[str, StickWidget]):
        self.stick_context_menu.emit(sender['stick_widget'], self)

    def show_overlay_message(self, msg: Optional[str]):
        if msg is None:
            self.overlay_message.setVisible(False)
            self.blur_eff.setEnabled(False)
            return
        self.overlay_message.setText(msg)
        self.overlay_message.setPos(
            self.pixmap.boundingRect().center() -
            QPointF(0.5 * self.overlay_message.boundingRect().width(), 0.5 *
                    self.overlay_message.boundingRect().height()))
        self.overlay_message.setVisible(True)
        self.blur_eff.setEnabled(True)

    def show_status_message(self, msg: Optional[str]):
        if msg is None:
            self.control_widget.set_title_text(self.camera.folder.name)
        else:
            self.control_widget.set_title_text(msg)

    def update_stick_box(self):
        left = 9000
        right = 0
        top = 9000
        bottom = -1

        for stick in self.camera.sticks:
            left = min(left, min(stick.top[0], stick.bottom[0]))
            right = max(right, max(stick.top[0], stick.bottom[0]))
            top = min(top, min(stick.top[1], stick.bottom[1]))
            bottom = max(bottom, max(stick.top[1], stick.bottom[1]))
        left -= 100
        right += 100
        top -= 100
        bottom += 100
        self.stick_box.setRect(left, top, right - left, bottom - top)
        pen = QPen(QColor(0, 100, 200, 200))
        pen.setWidth(2)
        pen.setStyle(Qt.DashLine)
        self.stick_box.setPen(pen)

    def set_stick_edit_mode(self, is_edit: bool):
        if is_edit:
            self.update_stick_box()
            self.stick_box_start_pos = self.stick_box.pos()
            for sw in self.stick_widgets:
                sw.setParentItem(self.stick_box)
        else:
            offset = self.stick_box.pos() - self.stick_box_start_pos
            for sw in self.stick_widgets:
                stick = sw.stick
                stick.translate(np.array([int(offset.x()), int(offset.y())]))
                sw.setParentItem(self)
                sw.set_stick(stick)
            self.stick_box.setParentItem(None)
            self.stick_box = QGraphicsRectItem(self)
            self.stick_box.setFlag(QGraphicsItem.ItemIsMovable, True)
            self.stick_box.setVisible(False)
        self.stick_box.setVisible(is_edit)

    def keyPressEvent(self, event: QKeyEvent) -> None:
        pass

    def keyReleaseEvent(self, event: QKeyEvent) -> None:
        if event.key() in [Qt.Key_Right, Qt.Key_Tab, Qt.Key_Space]:
            self.control_widget.next_photo_btn.click_button(True)
        elif event.key() in [Qt.Key_Left]:
            self.control_widget.prev_photo_btn.click_button(True)
        elif event.key() == Qt.Key_S:
            self.enter_pressed.emit()
Ejemplo n.º 32
0
class ActiveSliceItem(QGraphicsRectItem):
    """ActiveSliceItem for the Path View"""

    def __init__(self, part_item, active_base_index):
        super(ActiveSliceItem, self).__init__(part_item)
        self._part_item = part_item
        self._getActiveTool = part_item._getActiveTool
        self._active_slice = 0
        self._low_drag_bound = 0
        self._high_drag_bound = self.part().maxBaseIdx()
        self._controller = ActiveSliceItemController(self, part_item.part())

        self._label = QGraphicsSimpleTextItem("", parent=self)
        self._label.setPos(0, -18)
        self._label.setFont(_FONT)
        self._label.setBrush(_LABEL_BRUSH)
        self._label.hide()

        self.setFlag(QGraphicsItem.ItemIsMovable)
        self.setAcceptHoverEvents(True)
        self.setZValue(styles.ZACTIVESLICEHANDLE)
        self.setRect(QRectF(0, 0, _BASE_WIDTH,\
                      self._part_item.boundingRect().height()))
        self.setPos(active_base_index*_BASE_WIDTH, 0)
        self.setBrush(_BRUSH)
        self.setPen(_PEN)

        # reuse select tool methods for other tools
        self.addSeqToolMousePress = self.selectToolMousePress
        self.addSeqToolMouseMove = self.selectToolMouseMove
        self.breakToolMousePress = self.selectToolMousePress
        self.breakToolMouseMove = self.selectToolMouseMove
        self.insertionToolMousePress = self.selectToolMousePress
        self.insertionToolMouseMove = self.selectToolMouseMove
        self.paintToolMousePress = self.selectToolMousePress
        self.paintToolMouseMove = self.selectToolMouseMove
        self.pencilToolMousePress = self.selectToolMousePress
        self.pencilToolMouseMove = self.selectToolMouseMove
        self.skipToolMousePress = self.selectToolMousePress
        self.skipToolMouseMove = self.selectToolMouseMove
    # end def

    ### SLOTS ###
    def strandChangedSlot(self, sender, vh):
        pass
    # end def

    def updateRectSlot(self, part):
        bw = _BASE_WIDTH
        new_rect = QRectF(0, 0, bw,\
                    self._part_item.virtualHelixBoundingRect().height())
        if new_rect != self.rect():
            self.setRect(new_rect)
        self._hideIfEmptySelection()
        self.updateIndexSlot(part, part.activeBaseIndex())
        return new_rect
    # end def

    def updateIndexSlot(self, part, base_index):
        """The slot that receives active slice changed notifications from
        the part and changes the receiver to reflect the part"""
        label = self._label
        bw = _BASE_WIDTH
        bi = util.clamp(int(base_index), 0, self.part().maxBaseIdx())
        self.setPos(bi * bw, -styles.PATH_HELIX_PADDING)
        self._active_slice = bi
        if label:
            label.setText("%d" % bi)
            label.setX((bw - label.boundingRect().width()) / 2)
    # end def

    ### ACCESSORS ###
    def activeBaseIndex(self):
        return self.part().activeBaseIndex()
    # end def

    def part(self):
        return self._part_item.part()
    # end def

    def partItem(self):
        return self._part_item
    # end def

    ### PUBLIC METHODS FOR DRAWING / LAYOUT ###
    def removed(self):
        scene = self.scene()
        scene.removeItem(self._label)
        scene.removeItem(self)
        self._part_item = None
        self._label = None
        self._controller.disconnectSignals()
        self.controller = None
    # end def

    def resetBounds(self):
        """Call after resizing virtualhelix canvas."""
        self._high_drag_bound = self.part().maxBaseIdx()
    # end def

    ### PRIVATE SUPPORT METHODS ###
    def _hideIfEmptySelection(self):
        vis = self.part().numberOfVirtualHelices() > 0
        self.setVisible(vis)
        self._label.setVisible(vis)
    # end def

    def _setActiveBaseIndex(self, base_index):
        self.part().setActiveBaseIndex(base_index)
    # end def

    ### EVENT HANDLERS ###
    def hoverEnterEvent(self, event):
        self.setCursor(Qt.OpenHandCursor)
        self._part_item.updateStatusBar("%d" % self.part().activeBaseIndex())
        QGraphicsItem.hoverEnterEvent(self, event)
    # end def

    def hoverLeaveEvent(self, event):
        self.setCursor(Qt.ArrowCursor)
        self._part_item.updateStatusBar("")
        QGraphicsItem.hoverLeaveEvent(self, event)
    # end def

    def mousePressEvent(self, event):
        """
        Parses a mousePressEvent, calling the approproate tool method as
        necessary. Stores _move_idx for future comparison.
        """
        if event.button() != Qt.LeftButton:
            event.ignore()
            QGraphicsItem.mousePressEvent(self, event)
            return
        self.scene().views()[0].addToPressList(self)
        self._move_idx = int(floor((self.x() + event.pos().x()) / _BASE_WIDTH))
        tool_method_name = self._getActiveTool().methodPrefix() + "MousePress"
        if hasattr(self, tool_method_name):  # if the tool method exists
            modifiers = event.modifiers()
            getattr(self, tool_method_name)(modifiers)  # call tool method

    def mouseMoveEvent(self, event):
        """
        Parses a mouseMoveEvent, calling the approproate tool method as
        necessary. Updates _move_idx if it changed.
        """
        tool_method_name = self._getActiveTool().methodPrefix() + "MouseMove"
        if hasattr(self, tool_method_name):  # if the tool method exists
            idx = int(floor((self.x() + event.pos().x()) / _BASE_WIDTH))
            if idx != self._move_idx:  # did we actually move?
                modifiers = event.modifiers()
                self._move_idx = idx
                getattr(self, tool_method_name)(modifiers, idx)  # call tool method

    def customMouseRelease(self, event):
        """
        Parses a mouseReleaseEvent, calling the approproate tool method as
        necessary. Deletes _move_idx if necessary.
        """
        tool_method_name = self._getActiveTool().methodPrefix() + "MouseRelease"
        if hasattr(self, tool_method_name):  # if the tool method exists
            modifiers = event.modifiers()
            x = event.pos().x()
            getattr(self, tool_method_name)(modifiers, x)  # call tool method
        if hasattr(self, '_move_idx'):
            del self._move_idx

    ### TOOL METHODS ###
    def selectToolMousePress(self, modifiers):
        """
        Set the allowed drag bounds for use by selectToolMouseMove.
        """
        if (modifiers & Qt.AltModifier) and (modifiers & Qt.ShiftModifier):
            self.part().undoStack().beginMacro("Auto-drag Scaffold(s)")
            for vh in self.part().getVirtualHelices():
                # SCAFFOLD
                # resize 3' first
                for strand in vh.scaffoldStrandSet():
                    idx5p = strand.idx5Prime()
                    idx3p = strand.idx3Prime()
                    if not strand.hasXoverAt(idx3p):
                        lo, hi = strand.getResizeBounds(idx3p)
                        if strand.isDrawn5to3():
                            strand.resize((idx5p, hi))
                        else:
                            strand.resize((lo, idx5p))
                # resize 5' second
                for strand in vh.scaffoldStrandSet():
                    idx5p = strand.idx5Prime()
                    idx3p = strand.idx3Prime()
                    if not strand.hasXoverAt(idx5p):
                        lo, hi = strand.getResizeBounds(idx5p)
                        if strand.isDrawn5to3():
                            strand.resize((lo, idx3p))
                        else:
                            strand.resize((idx3p, hi))
                # STAPLE
                # resize 3' first
                for strand in vh.stapleStrandSet():
                    idx5p = strand.idx5Prime()
                    idx3p = strand.idx3Prime()
                    if not strand.hasXoverAt(idx3p):
                        lo, hi = strand.getResizeBounds(idx3p)
                        if strand.isDrawn5to3():
                            strand.resize((idx5p, hi))
                        else:
                            strand.resize((lo, idx5p))
                # resize 5' second
                for strand in vh.stapleStrandSet():
                    idx5p = strand.idx5Prime()
                    idx3p = strand.idx3Prime()
                    if not strand.hasXoverAt(idx3p):
                        lo, hi = strand.getResizeBounds(idx5p)
                        if strand.isDrawn5to3():
                            strand.resize((lo, idx3p))
                        else:
                            strand.resize((idx3p, hi))

            self.part().undoStack().endMacro()
    # end def

    def selectToolMouseMove(self, modifiers, idx):
        """
        Given a new index (pre-validated as different from the prev index),
        calculate the new x coordinate for self, move there, and notify the
        parent strandItem to redraw its horizontal line.
        """
        idx = util.clamp(idx, self._low_drag_bound, self._high_drag_bound)
        x = int(idx * _BASE_WIDTH)
        self.setPos(x, self.y())
        self.updateIndexSlot(None, idx)
        self._setActiveBaseIndex(idx)
        self._part_item.updateStatusBar("%d" % self.part().activeBaseIndex())
Ejemplo n.º 33
0
class GAction(QtWidgets.QGraphicsPathItem, GTooltipBase):
    """Base class for all graphical actions."""
    def __init__(self, g_data_item, w_data_item, parent=None, eval_gui=None, appending_ports=True):
        """Initializes GAction.
        :param g_data_item: Object which holds data describing graphical properties of this GAction.
        :param w_data_item: Object which holds data about action in workflow.
        :param parent: Action which holds this subaction: this GAction is inside parent GAction.
        """
        super(GAction, self).__init__(parent)
        self._width = g_data_item.data(GActionData.WIDTH)
        self._height = g_data_item.data(GActionData.HEIGHT)
        self.in_ports = []
        self.out_ports = []
        self.eval_gui = eval_gui
        self._hide_name = False

        self.appending_ports = appending_ports

        self.setPos(QtCore.QPoint(g_data_item.data(GActionData.X), g_data_item.data(GActionData.Y)))

        self.setPen(QtGui.QPen(QtCore.Qt.black))
        self.setBrush(QtCore.Qt.darkGray)
        self.setFlag(self.ItemIsMovable)
        self.setFlag(self.ItemIsSelectable)
        self.setFlag(self.ItemSendsGeometryChanges)
        self.setZValue(0.0)

        self.resize_handle_width = 6

        self.type_name = QGraphicsSimpleTextItem(w_data_item.action_name, self)
        self.type_name.setPos(QtCore.QPoint(self.resize_handle_width, GPort.SIZE / 2))
        self.type_name.setBrush(QtCore.Qt.white)

        self._name = EditableLabel(g_data_item.data(GActionData.NAME), self)

        self.background = GActionBackground(self)
        self.background.setZValue(1.0)

        self.setCacheMode(self.DeviceCoordinateCache)

        self.g_data_item = g_data_item
        self.w_data_item = w_data_item

        self.update_ports()

        self.level = 0
        self.height = self.height
        self.width = self.width

        self.progress = 0



    def has_const_params(self):
        if len(self.w_data_item.parameters.parameters) > 0:
            return self.w_data_item.parameters.parameters[-1].name is not None
        else:
            return True

    def update_ports(self):
        if len(self.w_data_item.parameters.parameters) > 0:
            self._add_ports(len(self.w_data_item.arguments), not self.has_const_params())
        else:
            self._add_ports(len(self.w_data_item.arguments))

    def __repr__(self):
        return self.name + "\t" + str(self.level)

    def hide_name(self, boolean):
        self._hide_name = boolean
        if boolean:
            self._name.setParentItem(None)
            self._name.hide()
        else:
            self._name.setParentItem(self)
            self._name.show()
        self._height = self.height - self.inner_area().height()
        self.position_ports()
        self.update_gfx()

    @property
    def status(self):
        return self.background.status

    @status.setter
    def status(self, status):
        self.background.status = status
        self.setBrush(self.background.COLOR_PALETTE[self.status])
        self.update()

    @property
    def progress(self):
        return self.background.progress

    @progress.setter
    def progress(self, percent):
        self.background.update_gfx()
        self.background.progress = percent

    @property
    def name(self):
        return self._name.toPlainText()

    @name.setter
    def name(self, name):
        self._name.setPlainText(name)

    @property
    def width(self):
        return self._width

    @width.setter
    def width(self, value):
        self._width = max(value, self.width_of_ports(),
                          self._name.boundingRect().width() + 2 * self.resize_handle_width,
                          self.type_name.boundingRect().width() + 2 * self.resize_handle_width)
        self.position_ports()
        self.update_gfx()
        # self.resize_handles.update_handles()

    @property
    def height(self):
        return self._height

    @height.setter
    def height(self, value):
        self._height = max(value, self._name.boundingRect().height() + GPort.SIZE +
                           self.type_name.boundingRect().height() + GPort.SIZE)
        self.position_ports()
        self.update_gfx()
        #self.resize_handles.update_handles()


    def boundingRect(self):
        return super(GAction, self).boundingRect().united(self.childrenBoundingRect())

    def next_actions(self):
        ret = []
        for port in self.out_ports:
            for conn in port.connections:
                item = conn.port2.parentItem()
                if item not in ret:
                    ret.append(item)
        return ret

    def previous_actions(self):
        ret = []
        for port in self.in_ports:
            for conn in port.connections:
                item = conn.port1.parentItem()
                if item not in ret:
                    ret.append(item)
        return ret

    def name_change(self):
        self.scene().update()
        self.width = self.width

    def name_has_changed(self):
        if not self.scene().action_name_changed(self.g_data_item, self.name) or self.name == "":
            return False
        self.width = self.width
        self.w_data_item.name(self.name)
        self.scene().update()
        return True

    def width_has_changed(self):
        self.scene().action_model.width_changed(self.g_data_item, self.width)

    def height_has_changed(self):
        self.scene().action_model.height_changed(self.g_data_item, self.height)

    def get_port(self, input, index):
        if input:
            return self.in_ports[index]
        else:
            return self.out_ports[index]

    def _add_ports(self, n_ports, appending=False):
        for i in range(n_ports):
            self.add_g_port(True, "Input Port" + str(i))
        if appending and self.appending_ports:
            self.add_g_port(True, "Appending port")
            self.in_ports[-1].appending_port = True

        self.add_g_port(False, "Output Port")

    def inner_area(self):
        """Returns rectangle of the inner area of GAction."""
        return QRectF(self.resize_handle_width, GPort.SIZE / 2 + self.type_name.boundingRect().height() + 4,
                      self.width - 2 * self.resize_handle_width,
                      self.height - GPort.SIZE - self.type_name.boundingRect().height() - 4)

    def moveBy(self, dx, dy):
        super(GAction, self).moveBy(dx, dy)
        self.scene().move(self.g_data_item, self.x() + dx, self.y() + dy)

    def mousePressEvent(self, press_event):
        super(GAction, self).mousePressEvent(press_event)
        self.setCursor(QtCore.Qt.ClosedHandCursor)
        if press_event.button() == Qt.RightButton:
            self.setSelected(True)

    def mouseReleaseEvent(self, release_event):
        super(GAction, self).mouseReleaseEvent(release_event)
        self.setCursor(QtCore.Qt.OpenHandCursor)
        temp = release_event.buttonDownScenePos(Qt.LeftButton)
        temp2 = release_event.pos()
        if release_event.buttonDownScenePos(Qt.LeftButton) != self.mapToScene(release_event.pos()):
            for item in self.scene().selectedItems():
                if self.scene().is_action(item):
                    self.scene().move(item.g_data_item, item.x(), item.y())

    def mouseDoubleClickEvent(self, event):
        if self.eval_gui is None:
            if self._name.contains(self.mapToItem(self._name, event.pos())):
                self._name.mouseDoubleClickEvent(event)
        else:
            self.eval_gui.double_click(self)

    def itemChange(self, change_type, value):
        """Update all connections which are attached to this action."""
        if change_type == self.ItemPositionHasChanged:

            for port in self.ports():
                for conn in port.connections:
                    conn.update_gfx()

        '''
        elif change_type == self.ItemParentChange:
            self.setPos(self.mapToItem(value, self.mapToScene(self.pos())))
        '''
        return super(GAction, self).itemChange(change_type, value)

    def paint(self, painter, item, widget=None):
        """Update model of this GAction if necessary."""
        #self.setBrush(self.background.COLOR_PALETTE[self.status])
        super(GAction, self).paint(painter, item, widget)

    def paint_pixmap(self):
        progress = self.progress
        status = self.status
        self.progress = 0
        self.status = ActionStatus.IDLE
        rect = self.boundingRect()
        pixmap = QPixmap(rect.size().toSize())
        pixmap.fill(Qt.transparent)

        painter = QPainter(pixmap)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.translate(-rect.topLeft())

        for child in self.childItems():
            if child.flags() & QGraphicsItem.ItemStacksBehindParent:
                painter.save()
                painter.translate(child.mapToParent(self.pos()))
                child.paint(painter, QStyleOptionGraphicsItem(), None)
                painter.restore()

        self.paint(painter, QStyleOptionGraphicsItem())
        for child in self.childItems():
            if not child.flags() & QGraphicsItem.ItemStacksBehindParent:
                painter.save()
                painter.translate(child.mapToParent(self.pos()))
                child.paint(painter, QStyleOptionGraphicsItem(), None)
                painter.restore()

        painter.end()
        self.progress = progress
        self.status = status
        return pixmap

    def update_gfx(self):
        """Updates model of the GAction."""
        self.prepareGeometryChange()
        p = QtGui.QPainterPath()
        p.addRoundedRect(QtCore.QRectF(0, 0, self.width, self.height), 6, 6)
        if not self._hide_name:
            p.addRoundedRect(self.inner_area(), 4, 4)
        self.setPath(p)
        self.update()
        self.background.update_gfx()

    def add_g_port(self, is_input, name=""):
        """Adds a port to this GAction.
        :param is_input: Decides if the new port will be input or output.
        """
        if is_input:
            self.in_ports.append(GInputPort(len(self.in_ports), QtCore.QPoint(0, 0), name, self))
        else:
            self.out_ports.clear()
            self.out_ports.append(GOutputPort(len(self.out_ports), QtCore.QPoint(0, 0), name, self))

        self.width = self.width

    def position_ports(self):
        if len(self.in_ports):
            space = self.width / (len(self.in_ports))
            for i in range(len(self.in_ports)):
                self.in_ports[i].setPos(QtCore.QPoint((i + 0.5) * space - GPort.RADIUS, -GPort.RADIUS))

        if len(self.out_ports):
            space = self.width / (len(self.out_ports))
            for i in range(len(self.out_ports)):
                self.out_ports[i].setPos(QtCore.QPoint((i + 0.5) * space - GPort.RADIUS, self.height - GPort.RADIUS))

    def width_of_ports(self):
        return max(len(self.in_ports) * GPort.SIZE, len(self.out_ports) * GPort.SIZE)

    def ports(self):
        """Returns input and output ports."""
        return self.in_ports + self.out_ports

    def get_arg_action(self, arg):
        index = self.w_data_item.arguments.index(arg)
        if len(self.in_ports[index].connections) == 1:
            return self.in_ports[index].connections[0].port1.parentItem()
        else:
            return None
Ejemplo n.º 34
0
class IndicatorIconView(QGraphicsPixmapItem):
    def __init__(self,
                 parent: ViewBox,
                 icon_path: str,
                 icon_pos: int,
                 color: Optional[List[int]] = None,
                 message: str = ""):
        """An indicator icon for a pyqtgraph ViewBox

        The icon loaded from icon_path will be displayed in the low right corner of the ViewBox.

        :param parent: ViewBox to place indicator in
        :param icon_path: path to icon
        :param icon_pos: position index. Counting from 0 in lower right.
        """
        super().__init__()

        self.parent = parent
        self.icon_pos = icon_pos

        self.label = QGraphicsSimpleTextItem(message)
        self.label.setVisible(False)
        self.parent.scene().addItem(self.label)

        self.set_icon(icon_path, color)
        self.icon_size = [32, 32]

        self.parent.scene().addItem(self)

        self.position_icon()
        self.parent.sigResized.connect(self.position_icon)
        self.setVisible(False)
        self.setAcceptHoverEvents(True)

        self.connected_overlay = None

        self.actions: List[QAction] = []

    def set_icon(self, icon_path: str, color: Optional[List[int]] = None):
        if color is not None:
            image_data = skio.imread(icon_path, plugin="imageio")
            # Set the RGB part to the red channel multiplied by the requested color
            red_channel = image_data[:, :, 0] / 255
            image_data[:, :, 0] = red_channel * color[0]
            image_data[:, :, 1] = red_channel * color[1]
            image_data[:, :, 2] = red_channel * color[2]

            h = image_data.shape[0]
            w = image_data.shape[1]
            image_qi = QImage(image_data.data, w, h, 4 * w,
                              QImage.Format_RGBA8888)

            image_pm = QPixmap.fromImage(image_qi)

            self.label.setBrush(QColor(*color))
        else:
            image_pm = QPixmap(icon_path)
        self.setPixmap(image_pm)

    def position_icon(self):
        # The size of the imageview we are putting the icon ing
        scene_size = self.parent.size()
        # The position of the image within the scene
        scene_pos = self.parent.scenePos()
        # Lower right corner in scene pixel coordinates
        corner_pos_x = scene_size.width() + scene_pos.x()
        corner_pos_y = scene_size.height() + scene_pos.y()

        icon_pos_x = corner_pos_x - self.icon_size[0] * (1 +
                                                         self.icon_pos) - 10
        icon_pos_y = corner_pos_y - self.icon_size[1] - 30
        self.setOffset(icon_pos_x, icon_pos_y)

        label_width = self.label.boundingRect().width()
        self.label.setPos(corner_pos_x - label_width,
                          icon_pos_y - self.icon_size[0])

    def hoverEnterEvent(self, event):
        if self.connected_overlay is not None:
            self.connected_overlay.setVisible(True)
        self.label.setVisible(True)

    def hoverLeaveEvent(self, event):
        if self.connected_overlay is not None:
            self.connected_overlay.setVisible(False)
        self.label.setVisible(False)

    def add_actions(self, actions: List[Tuple[str, Callable]]):
        for text, method in actions:
            action = QAction(text)
            action.triggered.connect(method)
            self.actions.append(action)

    def mouseClickEvent(self, event):
        event.accept()
        if self.actions:
            qm = QMenu()
            for action in self.actions:
                qm.addAction(action)

            qm.exec(event.screenPos().toQPoint())
Ejemplo n.º 35
0
    def game_update(self):
        self.player1.game_update(self.keys_pressed)
        self.player2.game_update(self.keys_pressed)

        for e in self.enemies:
            # ako je neprijatelj zavrsio sa padanjem, brisemo ga
            if e.frames == -1:
                self.removeItem(e)
                self.enemies.remove(e)
                continue
            # ako je neprijatelj izabran za padanje, nastavlja da pada
            if e.chosen:
                e.collapse()

            # igrac 1 pogodio neprijatelja
            if e.x() <= self.bullet1.x() <= e.x() + 32:
                if e.y() <= self.bullet1.y() <= e.y() + 26:
                    if e.powerUp:
                        temp = randint(0, 3)
                        if temp == 0:
                            if self.player1.speed == 2:
                                self.removeItem(self.player1PowerDown)
                            self.player1.speed = 8
                            self.player1PowerUp.setPos(770, 130)
                            self.addItem(self.player1PowerUp)
                        elif temp == 1:
                            if self.player1.speed == 8:
                                self.removeItem(self.player1PowerUp)
                            self.player1.speed = 2
                            self.player1PowerDown.setPos(770, 130)
                            self.addItem(self.player1PowerDown)
                        elif temp == 2:
                            if self.player1.lives == 3:
                                pass
                            elif self.player1.lives == 2:
                                self.livesPlayer1.append(LifePlayer1(760, 175))
                                self.player1.lives += 1
                                self.addItem(self.livesPlayer1[-1])
                            elif self.player1.lives == 1:
                                self.livesPlayer1.append(LifePlayer1(720, 175))
                                self.player1.lives += 1
                                self.addItem((self.livesPlayer1[-1]))
                            else:
                                pass
                        else:
                            self.player1Score += 100
                            self.player1Scores.setText("Score: \n" +
                                                       str(self.player1Score))
                    self.removeItem(e)
                    self.enemies.remove(e)
                    self.removeItem(self.bullet1)
                    self.bullet1.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
                    self.addItem(self.bullet1)
                    self.player1Score += 10
                    self.player1Scores.setText("Score: \n" +
                                               str(self.player1Score))
                    continue

            # igrac 2 pogodio neprijatelja
            if e.x() <= self.bullet2.x() <= e.x() + 32:
                if e.y() <= self.bullet2.y() <= e.y() + 26:
                    if e.powerUp:
                        temp = randint(0, 3)
                        if temp == 0:
                            if self.player2.speed == 2:
                                self.removeItem(self.player2PowerDown)
                            self.player2.speed = 8
                            self.player2PowerUp.setPos(770, 330)
                            self.addItem(self.player2PowerUp)
                        elif temp == 1:
                            if self.player2.speed == 8:
                                self.removeItem(self.player2PowerUp)
                            self.player2.speed = 2
                            self.player2PowerDown.setPos(770, 330)
                            self.addItem(self.player2PowerDown)
                        elif temp == 2:
                            if self.player2.lives == 3:
                                pass
                            elif self.player2.lives == 2:
                                self.livesPlayer2.append(LifePlayer2(760, 375))
                                self.player2.lives += 1
                                self.addItem(self.livesPlayer2[-1])
                            elif self.player2.lives == 1:
                                self.livesPlayer2.append(LifePlayer2(720, 375))
                                self.player2.lives += 1
                                self.addItem((self.livesPlayer2[-1]))
                            else:
                                pass
                        else:
                            self.player2Score += 100
                            self.player2Scores.setText("Score: \n" +
                                                       str(self.player2Score))
                    self.removeItem(e)
                    self.enemies.remove(e)
                    self.removeItem(self.bullet2)
                    self.bullet2.setPos(SCREEN_WIDTH, SCREEN_HEIGHT)
                    self.addItem(self.bullet2)
                    self.player2Score += 10
                    self.player2Scores.setText("Score: \n" +
                                               str(self.player2Score))
                    continue

            # na igraca 1 se obrusio neprijatelj
            if self.player1.y() <= e.y() + 26 <= self.player1.y() + 53:
                if self.player1.x() <= e.x(
                ) <= self.player1.x() + 69 or self.player1.x(
                ) <= e.x() + 32 <= self.player1.x() + 69:
                    if self.player1.lives > 0:
                        if self.player1.speed == 8:
                            self.removeItem(self.player1PowerUp)
                        elif self.player1.speed == 2:
                            self.removeItem(self.player1PowerDown)
                        self.player1.speed = 4
                        e.frames = -1
                        self.player1.lives -= 1
                        self.removeItem(self.livesPlayer1[-1])
                        self.livesPlayer1.remove(self.livesPlayer1[-1])
                        self.player1.setPos(20, 530)
                        if self.player1.lives <= 0:
                            self.removeItem(self.player1)
                            if self.player1.speed == 8:
                                self.removeItem(self.player1PowerUp)
                            elif self.player1.speed == 2:
                                self.removeItem(self.player1PowerDown)
                            if self.player2.lives > 0:
                                self.winner = 2

            # na igraca 2 se obrusio neprijatelj
            if self.player2.y() <= e.y() + 26 <= self.player2.y() + 53:
                if self.player2.x() <= e.x(
                ) <= self.player2.x() + 69 or self.player2.x(
                ) <= e.x() + 32 <= self.player2.x() + 69:
                    if self.player2.lives > 0:
                        if self.player2.speed == 8:
                            self.removeItem(self.player1PowerUp)
                        elif self.player2.speed == 2:
                            self.removeItem(self.player2PowerDown)
                        self.player2.speed = 4
                        e.frames = -1
                        self.player2.lives -= 1
                        self.removeItem(self.livesPlayer2[-1])
                        self.livesPlayer2.remove(self.livesPlayer2[-1])
                        self.player2.setPos(589, 530)
                        if self.player2.lives <= 0:
                            self.removeItem(self.player2)
                            if self.player2.speed == 8:
                                self.removeItem(self.player2PowerUp)
                            elif self.player2.speed == 2:
                                self.removeItem(self.player2PowerDown)
                            if self.player1.lives > 0:
                                self.winner = 1

        # igraca 1 pogodio laser neprijatelja
        if self.player1.x() + 69 >= self.bulletEnemy.x() >= self.player1.x():
            if self.player1.y() + 53 >= self.bulletEnemy.y() >= self.player1.y(
            ):
                if self.player1.lives > 0:
                    if self.player1.speed == 8:
                        self.removeItem(self.player1PowerUp)
                    elif self.player1.speed == 2:
                        self.removeItem(self.player1PowerDown)
                    self.player1.speed = 4
                    self.bulletEnemy.active = False
                    self.player1.lives -= 1
                    self.removeItem(self.livesPlayer1[-1])
                    self.livesPlayer1.remove(self.livesPlayer1[-1])
                    self.player1.setPos(20, 530)
                    if self.player1.lives <= 0:
                        self.removeItem(self.player1)
                        if self.player2.lives > 0:
                            self.winner = 2

        # igraca 2 pogodio laser neprijatelja
        if self.player2.x() + 69 >= self.bulletEnemy.x() >= self.player2.x():
            if self.player2.y() + 53 >= self.bulletEnemy.y() >= self.player2.y(
            ):
                if self.player2.lives > 0:
                    if self.player2.speed == 8:
                        self.removeItem(self.player2PowerUp)
                    elif self.player2.speed == 2:
                        self.removeItem(self.player2PowerDown)
                    self.player2.speed = 4
                    self.bulletEnemy.active = False
                    self.player2.lives -= 1
                    self.removeItem(self.livesPlayer2[-1])
                    self.livesPlayer2.remove(self.livesPlayer2[-1])
                    self.player2.setPos(589, 530)
                    if self.player2.lives <= 0:
                        self.removeItem(self.player2)
                        if self.player1.lives > 0:
                            self.winner = 1

        # pomeranje metaka
        self.bullet1.game_update(self.keys_pressed, self.player1)
        self.bullet2.game_update(self.keys_pressed, self.player2)
        try:
            self.bulletEnemy.game_update(self.enemies[self.randomEnemyIndex])
            if not self.bulletEnemy.active:
                self.randomEnemyIndex = randint(0, len(self.enemies))
        except:
            self.randomEnemyIndex = randint(0, len(self.enemies))

        # nasumicno biranje obrusavanja
        try:
            if randint(0, 500) == 0:
                self.enemies[randint(0, len(self.enemies))].chosen = True
        except:
            pass

        # kraj igre
        if self.player1.lives == 0 and self.player2.lives == 0:
            self.timer.stop()
            self.timerEnemy.stop()
            self.removeItem(self.bg)
            self.bg.setPos(-128, 0)
            self.addItem(self.bg)
            fontWinner = QFont()
            fontWinner.setPixelSize(40)
            textWinner = QGraphicsSimpleTextItem()
            textWinner.setFont(fontWinner)
            if self.winner == 1:
                textWinner.setText("WINNER PLAYER 1")
                textWinner.setBrush(QBrush(Qt.blue))
                self.player1.setPos(310, 300)
                self.addItem(self.player1)
            elif self.winner == 2:
                textWinner.setText("WINNER PLAYER 2")
                textWinner.setBrush(QBrush(Qt.red))
                self.player2.setPos(310, 300)
                self.addItem(self.player2)
            textWinner.setPos(180, 200)
            self.addItem(textWinner)

        # pobedjen nivo
        if len(self.enemies) == 0:
            self.timer.stop()
            self.timerEnemy.stop()
            if self.player1.lives > 0:
                self.removeItem(self.player1)
                self.removeItem(self.bullet1)
            if self.player2.lives > 0:
                self.removeItem(self.player2)
                self.removeItem(self.bullet2)
            self.removeItem(self.bulletEnemy)
            self.new_level()
Ejemplo n.º 36
0
class Scene(QGraphicsScene):
    entered = pyqtSignal([QGraphicsItem], [QGraphicsEllipseItem])
    leave = pyqtSignal([QGraphicsItem], [QGraphicsEllipseItem])
    move = pyqtSignal([QGraphicsItem], [QGraphicsEllipseItem])
    # press = pyqtSignal([QGraphicsItem],[QGraphicsEllipseItem])
    """Each instance holds all image and ellipse data"""
    def __init__(self, MainWindow, **keywords):
        # executes QGraphicsScene.__init__()
        super().__init__()

        # self.sceneCount=self.counter
        self.MainWindow = MainWindow
        self.keywords = keywords
        self.threshold = self.MainWindow.binary_sb.value()
        self.populated = False

        if 'path' in self.keywords.keys():
            self.getPathData(self.keywords['path'])
            self.binarize_image()
            self.findContours()
            self.image = Image(self.path)
            self.addItem(self.image)

        if 'headers' in self.keywords.keys():
            self.headx_px = self.keywords['headers'][0]
            self.heady_px = self.keywords['headers'][1]
            xheader = self.headx_px.split("_")
            yheader = self.heady_px.split("_")
            self.sceneID = list(set(xheader).intersection(set(yheader)))[0]
        else:
            self.headx_px = "%s_x" % self.filename
            self.heady_px = "%s_y" % self.filename
            self.sceneID = "%s" % (self.filename)

        self.dotCoords = {}
        if 'coords' in self.keywords.keys():
            self.pointCount = len(self.keywords['coords'][0])
            self.dotCoords['x_px'] = self.keywords['coords'][0]
            self.dotCoords['y_px'] = self.keywords['coords'][1]
        else:
            self.pointCount = 0

            self.dotCoords['x_px'] = [None] * len(
                self.MainWindow.pointData.index)
            self.dotCoords['y_px'] = [None] * len(
                self.MainWindow.pointData.index)

        if self.sceneID in self.MainWindow.scenes:
            self.sceneID = "%s_copy" % (self.sceneID)

        self.MainWindow.view_lw.addItem(self.sceneID)

    def setThreshold(self):
        self.threshold = self.MainWindow.binary_sb.value()

    def populateDotsOnLink(self):

        self.pointCount = 0
        for i in range(len(self.MainWindow.pointData.index)):
            self.circle = Ellipse(0, 0, 10, 10, self.pointCount)
            self.circle.setPos(self.dotCoords['x_px'][i] - 5,
                               self.dotCoords['y_px'][i] - 5)
            self.addItem(self.circle)
            self.pointCount += 1
        self.populated = True

    def linkView(self, path):

        if path[0] != '':

            self.getPathData(path[0])

            self.clear()

            self.image = Image(self.path)
            self.addItem(self.image)
            self.binarize_image()
            self.findContours()

            self.populateDotsOnLink()

    def getPathData(self, path):
        self.path = path
        self.filename_w_ext = os.path.basename(path)
        self.filename, file_extension = os.path.splitext(self.filename_w_ext)
        self.root = os.path.dirname(os.path.abspath(path))

    def remove_image(self):
        self.removeItem(self.image)

    def refresh_image(self, path):
        self.image = Image(self.path)
        self.addItem(self.image)

    def binarize_image(self):

        self.orig_image = cv2.imread(self.path)
        self.cnts_image = self.orig_image
        imageGray = cv2.cvtColor(self.orig_image, cv2.COLOR_BGR2GRAY)

        ret, self.cvBinaryImage = cv2.threshold(imageGray, self.threshold, 255,
                                                cv2.THRESH_BINARY_INV)

        self.binaryImagePath = self.root + "\\" + self.filename + '_binary.jpg'
        cv2.imwrite(self.binaryImagePath, self.cvBinaryImage)

        # self.binarySceneName='%s_binary' % str(self.sceneID)
        self.binaryImage = Image(self.binaryImagePath)

    def findContours(self):

        #Prevents a fatal crash due to version conflict in cv2.findContours
        try:

            self.cnts, hierachy = cv2.findContours(self.cvBinaryImage,
                                                   cv2.RETR_TREE,
                                                   cv2.CHAIN_APPROX_SIMPLE)
        except ValueError:
            ret, self.cnts, hierachy = cv2.findContours(
                self.cvBinaryImage, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

        self.good_cnts = []
        for c in self.cnts:

            if 5 <= cv2.contourArea(c) <= 500:
                self.good_cnts.append(c)
                cv2.drawContours(self.cnts_image, [c], -5, (255, 0, 0), 1)

                (xstart, ystart, w, h) = cv2.boundingRect(c)
                M = cv2.moments(c)
                try:
                    cx = int(M['m10'] / M['m00'])
                    cy = int(M['m01'] / M['m00'])
                    cv2.circle(self.cnts_image, (cx, cy), 2, (0, 0, 255), -1)
                except ZeroDivisionError:
                    continue

        self.cntsImagePath = self.root + "\\" + self.filename + '_cnts.jpg'
        cv2.imwrite(self.cntsImagePath, self.cnts_image)
        self.contourImage = Image(self.cntsImagePath)

    def clearView(self):
        self.removeItem(self.image)
        self.removeItem(self.binaryImage)
        self.removeItem(self.contourImage)

    def showBinaryImage(self):
        self.clearView()
        self.addItem(self.binaryImage)

    def showContourImage(self):
        self.clearView()
        self.addItem(self.contourImage)

    def showOriginalImage(self):
        self.clearView()
        self.addItem(self.image)

    def correct_centers(self):

        self.findContours()

        for idx, i in enumerate(self.items()):

            if isinstance(i, Ellipse):

                for c in self.good_cnts:
                    (xstart, ystart, w, h) = cv2.boundingRect(c)

                    x = i.pos().toPoint().x() + 5
                    y = i.pos().toPoint().y() + 5

                    if xstart <= x <= xstart + w and ystart <= y <= ystart + h:
                        M = cv2.moments(c)
                        try:
                            cx = int(M['m10'] / M['m00'])
                            cy = int(M['m01'] / M['m00'])

                            i.setX(cx - 5)
                            i.setY(cy - 5)
                            self.MainWindow.ellipseMove(i)
                            i.setBrush(QColor('green'))

                        except ZeroDivisionError:
                            continue

    def showCoords(self, event):
        try:
            self.removeItem(self.text)
            self.removeItem(self.dot)
        except AttributeError:
            pass
        p = self.MainWindow.View.mapToScene(event.x(), event.y())
        self.dot = QGraphicsEllipseItem(int(p.x()) - 3, int(p.y()) - 3, 6, 6)
        self.dot.setBrush(Qt.blue)
        self.addItem(self.dot)
        self.text = QGraphicsSimpleTextItem(
            "x%s_y%s" % (str(int(p.x()) + 5), str(int(p.y()) + 5)))
        self.text.setBrush(Qt.red)
        self.text.setPos(p.x(), p.y())
        self.addItem(self.text)
        # self.removeItem(self.text)

    def removeInfo(self, item):
        self.current_scene.removeItem(self.text)

    def add_point(self, event):

        try:
            self.path
        except AttributeError:
            self.MainWindow.errMessage = "Please link calibration point data with a calibration view"
            self.MainWindow.errorTitle = "Calibration view not linked"
            self.MainWindow.errorMsg()
            return None

        if self.pointCount == self.MainWindow.num_points:
            self.MainWindow.errMessage = "You have placed all the points listed in the calibration point file. If you wish to add more points, add more rows to the point file and start over."
            self.MainWindow.errorTitle = "Cannot place any more points"
            self.MainWindow.errorMsg()
            return None

        p = self.MainWindow.View.mapToScene(event.x(), event.y())
        self.circle = Ellipse(0, 0, 10, 10, self.pointCount)
        self.circle.setPos(p.x() - 5, p.y() - 5)
        self.addItem(self.circle)
        self.dotCoords['x_px'][self.pointCount] = int(p.x())
        self.dotCoords['y_px'][self.pointCount] = int(p.y())
        self.MainWindow.refreshTableData()
        self.pointCount += 1

    def updateTableOnEllipseMove(self, x, y, item):

        self.dotCoords['x_px'][item.count] = int(x)
        self.dotCoords['y_px'][item.count] = int(y)
        self.MainWindow.refreshTableData()
Ejemplo n.º 37
0
class ExplorerNode(BaseNode):
    def __init__(self, nx_node, center_pos, nx_pos, steps, steps_max):
        """
        Create node in the graph scene

        :param tuple nx_node: Node info
        :param center_pos: The position of the center node
        :param nx_pos: Position of the nodes in the graph
        :param int steps: The steps from the center identity
        :param int steps_max: The steps max of the graph
        """
        super().__init__(nx_node, nx_pos)

        self.steps = steps
        self.steps_max = steps_max
        self.highlighted = False

        # text inside ellipse
        self.text_item = QGraphicsSimpleTextItem(self)
        self.text_item.setText(self.text)
        # center ellipse around text
        self.setRect(
            0,
            0,
            self.text_item.boundingRect().width() * 2,
            self.text_item.boundingRect().height() * 2
        )

        #  set anchor to the center
        self.setTransform(
            QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0))
        # center text in ellipse
        self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0)

        # cursor change on hover
        self.setAcceptHoverEvents(True)
        self.setZValue(1)

        # animation and moves
        self.timeline = None
        self.loading_timer = QTimer()
        self.loading_timer.timeout.connect(self.next_tick)
        self.loading_counter = 0
        self._refresh_colors()
        self.setPos(center_pos)
        self.move_to(nx_pos)

    def _refresh_colors(self):
        """
        Refresh elements in the node
        """
        # color around ellipse
        outline_color = QColor('black')
        outline_style = Qt.SolidLine
        outline_width = 1
        if self.status_wallet:
            outline_color = QColor('grey')
            outline_width = 2
        if not self.status_member:
            outline_color = QColor('red')
            outline_style = Qt.SolidLine
        self.setPen(QPen(outline_color, outline_width, outline_style))

        if self.highlighted:
            text_color = QColor('grey')
        else:
            text_color = QColor('black')

        if self.status_wallet == NodeStatus.HIGHLIGHTED:
            text_color = QColor('grey')
        self.text_item.setBrush(QBrush(text_color))

        # create gradient inside the ellipse
        gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width())
        color = QColor()
        color.setHsv(120 - 60 / self.steps_max * self.steps,
                     180 + 50 / self.steps_max * self.steps,
                     60 + 170 / self.steps_max * self.steps)
        if self.highlighted:
            color = color.darker(200)
        color = color.lighter(math.fabs(math.sin(self.loading_counter / 100 * math.pi) * 100) + 100)
        gradient.setColorAt(0, color)
        gradient.setColorAt(1, color.darker(150))
        self.setBrush(QBrush(gradient))

    def move_to(self, nx_pos):
        """
        Move to corresponding position
        :param nx_pos:
        :return:
        """
        origin_x = self.x()
        origin_y = self.y()
        final_x = nx_pos[self.id][0]
        final_y = nx_pos[self.id][1]

        def frame_move(frame):
            value = self.timeline.valueForTime(self.timeline.currentTime())
            x = origin_x + (final_x - origin_x) * value
            y = origin_y + (final_y - origin_y) * value
            self.setPos(x, y)
            self.scene().node_moved.emit(self.id, x, y)

        def timeline_ends():
            self.setPos(final_x, final_y)
            self.timeline = None

        # Remember to hold the references to QTimeLine and QGraphicsItemAnimation instances.
        # They are not kept anywhere, even if you invoke QTimeLine.start().
        self.timeline = QTimeLine(1000)
        self.timeline.setFrameRange(0, 100)
        self.timeline.frameChanged.connect(frame_move)
        self.timeline.finished.connect(timeline_ends)

        self.timeline.start()

    def highlight(self):
        """
        Highlight the edge in the scene
        """
        self.highlighted = True
        self._refresh_colors()
        self.update(self.boundingRect())

    def neutralize(self):
        """
        Neutralize the edge in the scene
        """
        self.highlighted = False
        self._refresh_colors()
        self.update(self.boundingRect())

    def start_loading_animation(self):
        """
        Neutralize the edge in the scene
        """
        if not self.loading_timer.isActive():
            self.loading_timer.start(10)

    def stop_loading_animation(self):
        """
        Neutralize the edge in the scene
        """
        self.loading_timer.stop()
        self.loading_counter = 100
        self._refresh_colors()
        self.update(self.boundingRect())

    def next_tick(self):
        """
        Next tick
        :return:
        """
        self.loading_counter += 1
        self.loading_counter %= 100
        self._refresh_colors()
        self.update(self.boundingRect())
Ejemplo n.º 38
0
class MainWindow(QMainWindow, user_interface.Ui_MainWindow):
    """main user interface """
    def __init__(self, parent=None):

        super(MainWindow, self).__init__(parent)

        self.setupUi(self)
        self.setWindowTitle("Calibrate 3D")
        self.setWindowIcon(
            QIcon(os.path.dirname(os.path.abspath(__file__)) + '/dice.png'))

        self.scenes = {}
        self.calibrate = DLT(3, 2)
        self.tableCreated = False

        self.initUI()

    def initUI(self):

        #button connects
        self.addPointFile_b.clicked.connect(self.newGetCalibrationPoints)
        self.loadFilledTable_b.clicked.connect(self.readInTable)
        self.loadCal_b.clicked.connect(self.loadCalibration)
        self.newView_b.clicked.connect(self.new_add_scene)
        self.link_b.clicked.connect(self.linkView)
        self.correct_b.clicked.connect(self.button_correct_centers)
        self.binary_sb.valueChanged.connect(self.redo_binarization)
        self.saveTable_b.clicked.connect(self.saveTable)
        self.calibrate_b.clicked.connect(self.calibrate3D)
        self.loadTest_b.clicked.connect(self.loadTestTableData)
        self.testCal_b.clicked.connect(self.test3DCalibration)
        self.delete_b.clicked.connect(self.deleteView)
        self.saveTest_b.clicked.connect(self.saveTestData)
        self.saveCalibration_b.clicked.connect(self.saveCalibration)

        #list widget connects
        # self.view_lw.clicked.connect(self.change_scene)
        self.view_lw.currentRowChanged.connect(self.change_scene)
        self.original_rb.toggled.connect(self.change_scene)
        self.binary_rb.toggled.connect(self.change_scene)
        self.contour_rb.toggled.connect(self.change_scene)

        #other
        self.View.mouseDoubleClickEvent = self.add_point
        self.slider.setRange(1, 500)
        self.slider.setValue(100)
        self.slider.valueChanged[int].connect(self.onZoom)
        self.groupBox_8.setVisible(False)
        self.link_b.setVisible(False)
        self.radioButton_2.toggled['bool'].connect(self.link_b.setVisible)

    def linkView(self):

        if self.view_lw.count() == 0:
            self.errMessage = "No views available for linking."
            self.errorTitle = "Cannot link view"
            self.errorMsg()
            return None

        self.selectedItemText = self.view_lw.currentItem().text()
        self.current_scene = self.scenes[self.selectedItemText]

        path = QFileDialog.getOpenFileName(self,
                                           "Load image view",
                                           filter="Image Files( *.png *.jpg)")

        self.scenes[self.selectedItemText].linkView(path)
        self.change_scene()
        self.View.setScene(self.current_scene)

    def deleteView(self):

        try:
            self.selectedItemText = self.view_lw.currentItem().text()
        except AttributeError:
            self.errMessage = "Please click on the view to remove."
            self.errorTitle = "No view selected"
            self.errorMsg()
            return None
        xCol = str(self.scenes[self.selectedItemText].headx_px)
        yCol = str(self.scenes[self.selectedItemText].heady_px)
        self.pointData.drop(columns=[xCol, yCol], inplace=True)
        self.scenes.pop(self.selectedItemText)
        self.view_lw.takeItem(self.view_lw.currentRow())

        try:
            self.firstSceneKey = list(self.scenes.keys())[0]
            self.current_scene = self.scenes[self.firstSceneKey]
            self.current_scene.showOriginalImage()
            item = self.view_lw.findItems(self.current_scene.sceneID,
                                          Qt.MatchExactly)[0]
            item.setSelected(True)
            self.view_lw.setCurrentItem(item)
            self.View.setScene(self.current_scene)
        except IndexError:
            self.current_scene.clear()
        except AttributeError:
            pass

        self.tableWidget.setModel(PandasModel(self.pointData))

    """
    Table loading and manipulation methods
    """

    def newGetCalibrationPoints(self):

        self.promptSceneDelete()
        pointFilePath = QFileDialog.getOpenFileName(
            self, "Load point data file", filter="Text files( *.txt *.csv)")

        if pointFilePath[0] != '':

            self.pointData = pd.read_csv(pointFilePath[0])
            self.num_points = len(self.pointData.index)
            self.nmbViews = (len(self.pointData.columns) - 3) / 2
            if self.nmbViews > 0:
                self.errMessage = "Please load a file containing colums for only the point coordinates."
                self.errorTitle = "File contains view data!"
                self.errorMsg()
                return None
            self.tableWidget.setModel(PandasModel(self.pointData))
            self.tabWidget.setCurrentIndex(1)
            self.pointFile_l.setText(pointFilePath[0])

    def refreshTableData(self):

        for key in self.scenes:

            for inner_key in self.scenes[key].dotCoords:
                if inner_key == 'x_px':
                    self.pointData[self.scenes[key].headx_px] = self.scenes[
                        key].dotCoords[inner_key]
                if inner_key == 'y_px':
                    self.pointData[self.scenes[key].heady_px] = self.scenes[
                        key].dotCoords[inner_key]

        self.tableWidget.setModel(PandasModel(self.pointData))

    def promptSceneDelete(self):

        if self.view_lw.count() > 0:

            reply = QMessageBox.question(
                self, 'Continue?',
                'Loading a new calibration table will delete existing views, accept?',
                QMessageBox.Yes, QMessageBox.No)
            if reply == QMessageBox.Yes:
                self.scenes = {}
                self.view_lw.clear()
            else:
                return None

    def readInTable(self):

        self.promptSceneDelete()
        pointFilePath = QFileDialog.getOpenFileName(
            self,
            "Load populated point data file",
            filter="Text files( *.txt *.csv)")

        if pointFilePath[0] != '':
            self.pointData = pd.read_csv(pointFilePath[0])
            self.num_points = len(self.pointData.index)
            self.nmbViews = int((len(self.pointData.columns) - 3) / 2)
            self.headers = list(self.pointData.columns)

            if self.nmbViews < 2:
                self.errMessage = "File does not contain data sufficient for at least two views"
                self.errorTitle = "Not enough views in file"
                self.errorMsg()
                return None

            col = 3
            for i in range(self.nmbViews):
                colNames = []
                colNames.append(self.headers[col])
                colNames.append(self.headers[col + 1])

                coords = []
                coords.append(self.pointData[self.headers[col]])
                coords.append(self.pointData[self.headers[col + 1]])

                self.current_scene = Scene(self,
                                           coords=coords,
                                           headers=colNames)
                self.current_scene.entered.connect(self.displayInfo)
                self.current_scene.leave.connect(self.removeInfo)
                self.current_scene.move.connect(self.ellipseMove)

                self.scenes[self.current_scene.sceneID] = self.current_scene
                # self.View.setScene(self.current_scene)
                item = self.view_lw.findItems(self.current_scene.sceneID,
                                              Qt.MatchExactly)[0]
                item.setSelected(True)
                self.view_lw.setCurrentItem(item)
                # self.newView_b.setText("Add view")

                col += 2

            self.pointFile_l.setText(pointFilePath[0])
            self.tableWidget.setModel(PandasModel(self.pointData))
            self.tabWidget.setCurrentIndex(1)

    def saveTable(self):

        path = QFileDialog.getSaveFileName(self, 'Save File', '',
                                           'CSV(*.csv)')[0]
        self.pointData.to_csv(path, index=False)

    """
    View and Scene related methods
    """

    def new_add_scene(self):

        if not hasattr(self, 'pointData'):

            self.errMessage = "Please load a point file or a populate calibration file and then try again."
            self.errorTitle = "Cannot add view!"
            self.errorMsg()
            return None

        viewPath = QFileDialog.getOpenFileName(
            self, "Load image view", filter="Image Files( *.png *.jpg)")

        if viewPath[0] != '':

            self.current_scene = Scene(self, path=viewPath[0])
            self.current_scene.entered.connect(self.displayInfo)
            self.current_scene.leave.connect(self.removeInfo)
            self.current_scene.move.connect(self.ellipseMove)

            self.scenes[self.current_scene.sceneID] = self.current_scene
            self.View.setScene(self.current_scene)
            item = self.view_lw.findItems(self.current_scene.sceneID,
                                          Qt.MatchExactly)[0]
            item.setSelected(True)
            self.view_lw.setCurrentItem(item)
            self.newView_b.setText("Add view")

            self.pointData[self.current_scene.headx_px] = N.nan
            self.pointData[self.current_scene.heady_px] = N.nan
            self.tableWidget.setModel(PandasModel(self.pointData))

    def my_decorator(self):

        for count, scene in enumerate(self.scenes):

            if scene in self.selectedItemText:

                self.current_scene = self.scenes[scene]

    def change_scene(self):
        self.tabWidget.setCurrentIndex(0)
        try:
            self.selectedItemText = self.view_lw.currentItem().text()

            self.my_decorator()

            if not hasattr(self.current_scene, 'path'):
                emptyScene = QGraphicsScene()
                self.View.setScene(emptyScene)
                return None

            self.binary_sb.setValue(self.current_scene.threshold)

            if self.original_rb.isChecked() == True:
                self.current_scene.showOriginalImage()
            elif self.binary_rb.isChecked() == True:
                self.current_scene.showBinaryImage()
            elif self.contour_rb.isChecked() == True:
                self.current_scene.showContourImage()
            self.View.setScene(self.current_scene)
        except AttributeError:
            pass

    def redo_binarization(self):

        if not hasattr(self, 'pointData'):
            self.errMessage = "Please select a view then try again."
            self.errorTitle = "No view selected!"
            self.errorMsg()
            return None

        try:
            self.selectedItemText = self.view_lw.currentItem().text()

        except IndexError:
            self.errMessage = "Please click on a view to work with."
            self.errorTitle = "No view selected"
            self.errorMsg()
            return None
        except AttributeError:
            self.errMessage = "Please click on a view to work with."
            self.errorTitle = "No view selected"
            self.errorMsg()
            return None

        try:
            self.my_decorator()
            self.current_scene.setThreshold()
            self.current_scene.findContours()
            self.current_scene.binarize_image()
            self.change_scene()
        except AttributeError:
            pass

    def onZoom(self, value):
        val = value / 100
        self.View.resetTransform()
        self.View.scale(val, val)

    """
    Calibration marker methods
    """

    def add_point(self, event):
        self.current_scene.add_point(event)

    def showCoords(self, event):
        self.current_scene.showCoords(event)

    def button_correct_centers(self):
        try:
            self.current_scene.correct_centers()
            self.change_scene()
        except AttributeError:
            pass

    def displayInfo(self, item):
        self.text = QGraphicsSimpleTextItem(
            "P%s_x%s_y%s" %
            (str(item.count + 1), str(item.pos().toPoint().x() + 5),
             str(item.pos().toPoint().y() + 5)))
        self.text.setBrush(Qt.red)
        self.text.setPos(item.pos().toPoint().x() + 10,
                         item.pos().toPoint().y() + 10)
        self.current_scene.addItem(self.text)

    def removeInfo(self, item):
        self.current_scene.removeItem(self.text)

    def ellipseMove(self, item):
        item.setBrush(QColor('red'))
        self.current_scene.removeItem(self.text)
        x = str(item.pos().toPoint().x() + 5)
        y = str(item.pos().toPoint().y() + 5)

        self.current_scene.updateTableOnEllipseMove(x, y, item)

    """
    Calibration and testing methods
    """

    def calibrate3D(self):

        try:
            x = list(self.pointData['x'])
            y = list(self.pointData['y'])
            z = list(self.pointData['z'])

        except AttributeError:
            self.errMessage = "Fully populate the calibration table to continue."
            self.errorTitle = "Calibration table not correctly populated!"
            self.errorMsg()
            return None

        #set up xyz coords list
        xyz = []

        for i in range(len(x)):
            point = []
            point.append(x[i])
            point.append(y[i])
            point.append(z[i])
            print(point)
            xyz.append(point)

        px_coords = []
        for key in self.scenes:
            view_coords = []
            x_px = list(self.pointData[self.scenes[key].headx_px])
            y_px = list(self.pointData[self.scenes[key].heady_px])
            view_coords.append(x_px)
            view_coords.append(y_px)
            px_coords.append(view_coords)

        self.nmbDim = 3
        self.coefficients = []
        errors = []

        self.nmbCam = self.nmbViews

        #get parameters for each view
        for view in px_coords:
            uv = []
            for i in range(len(view[0])):

                pair = []
                pair.append(view[0][i])
                pair.append(view[1][i])
                uv.append(pair)
            L, err = self.calibrate.DLTcalib(self.nmbDim, xyz, uv)

            self.coefficients.append(L)
            errors.append(err)

    def loadTestTableData(self):

        pointFilePath = QFileDialog.getOpenFileName(
            self,
            "Load populated test table",
            filter="Text files( *.txt *.csv)")

        if pointFilePath[0] != '':
            self.testData = pd.read_csv(pointFilePath[0])
            self.numTestPoints = len(self.testData.index)
            self.numTestViews = int((len(self.testData.columns) - 3) / 2)
            self.testHeaders = list(self.testData.columns)

            if self.numTestViews < 2:
                self.errMessage = "File contains less than two views"
                self.errorTitle = "Not enough views in file"
                self.errorMsg()
                return None

        self.test_tableView.setModel(PandasModel(self.testData))

    def saveCalibration(self):

        try:
            test = self.coefficients

        except AttributeError:
            self.errMessage = "Perform a calibration and then try again."
            self.errorTitle = "No calibration available!"
            self.errorMsg()
            return None

        path = QFileDialog.getSaveFileName(self, 'Save File', '',
                                           'CSV(*.csv)')[0]
        if path:
            print(self.coefficients)
            self.coefficients_df = pd.DataFrame(self.coefficients)
            self.coefficients_df.to_csv(path,
                                        sep=',',
                                        index=False,
                                        header=False)

    def loadCalibration(self):
        pointFilePath = QFileDialog.getOpenFileName(
            self, "Load calibration file", filter="Text files( *.txt *.csv)")
        self.coefficients = []

        if pointFilePath[0] != '':
            self.dfCoefficients = pd.read_csv(pointFilePath[0], header=None)

            for index, row in self.dfCoefficients.iterrows():
                self.coefficients.append(N.asarray(list(row)))
        self.tabWidget.setCurrentIndex(2)

    def test3DCalibration(self):

        x = list(self.testData[self.testHeaders[0]])
        y = list(self.testData[self.testHeaders[1]])
        z = list(self.testData[self.testHeaders[2]])

        self.testXYZ = []
        for i in range(self.numTestPoints):
            testCoord = []
            testCoord.append(x[i])
            testCoord.append(y[i])
            testCoord.append(z[i])
            self.testXYZ.append(testCoord)

        testPxCoords = []
        col = 3
        for i in range(self.numTestViews):
            colNames = []

            colNames.append(self.testHeaders[col])
            colNames.append(self.testHeaders[col + 1])
            x_px = list(self.testData[self.testHeaders[col]])
            y_px = list(self.testData[self.testHeaders[col + 1]])

            coords = []
            for i in range(len(x_px)):
                pair = []
                pair.append(x_px[i])
                pair.append(y_px[i])
                coords.append(pair)

            testPxCoords.append(coords)
            col += 2

        xyz1234 = N.zeros((len(self.testXYZ), 3))
        print(self.coefficients)
        #use parameters to reconstruct input points
        for i in range(len(testPxCoords[0])):
            i_px_coords = []
            for view in testPxCoords:
                i_px_coords.append(view[i])
            try:
                xyz1234[i, :] = self.calibrate.DLTrecon(
                    3, self.numTestViews, self.coefficients, i_px_coords)
            except AttributeError:
                self.errMessage = "No calibration available"
                self.errorTitle = "Perform a calibration, then try again."
                self.errorMsg()
                return None
            except ValueError:
                self.errMessage = "Ensure you have loaded a valid calibration file and a valid marker test point file. The calibration file should have 12 columns and as many rows as were used to perform the calibration. The test point file should have 2x the number of views used to obtain the calibration plus 3 more columns for the object-space coordinates."
                self.errorTitle = "Calibration and test point files are incompatabile!"
                self.errorMsg()
                return None

        rec_xyz = pd.DataFrame(xyz1234, columns=['rec_x', 'rec_y', 'rec_z'])
        xyz = pd.DataFrame(self.testXYZ, columns=['x', 'y', 'z'])
        self.results = pd.concat([xyz, rec_xyz], axis=1)
        self.results['x_e'] = self.results['x'] - self.results['rec_x']
        self.results['y_e'] = self.results['y'] - self.results['rec_y']
        self.results['z_e'] = self.results['z'] - self.results['rec_z']

        self.xmean_l.setText(
            "%.4f" % ((self.results.x - self.results.rec_x)**2).mean()**.5)
        self.ymean_l.setText(
            "%.4f" % ((self.results.y - self.results.rec_y)**2).mean()**.5)
        self.zmean_l.setText(
            "%.4f" % ((self.results.z - self.results.rec_z)**2).mean()**.5)

        self.pointsTested_l.setText(str(self.numTestPoints))

        self.errorTitle = "Calibration test successful!"
        self.errMessage = "The test completed with success. If desired, consult the simple statistics below or save the test's results and postprocess with a third party application."
        self.errorMsg()
        # print(self.results)

        # print(N.mean(N.sqrt(N.sum((N.array(xyz1234)-N.array(xyz))**2,1))))

    def saveTestData(self):
        path = QFileDialog.getSaveFileName(self, 'Save File', '',
                                           'CSV(*.csv)')[0]
        if path:
            self.results.to_csv(path, sep=',', index=False)

    """
    Utility functions
    """

    def errorMsg(self):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Information)
        msg.setText(self.errMessage)
        msg.setWindowTitle(self.errorTitle)
        msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        retval = msg.exec_()
Ejemplo n.º 39
0
class Node(QGraphicsEllipseItem):
    def __init__(self, metadata, x_y):
        """
        Create node in the graph scene

        :param dict metadata: Node metadata
        :param x_y: Position of the node
        """
        # unpack tuple
        x, y = x_y

        super(Node, self).__init__()

        self.metadata = metadata
        self.id = metadata['id']
        self.status_wallet = self.metadata['status'] & NODE_STATUS_HIGHLIGHTED
        self.status_member = not self.metadata['status'] & NODE_STATUS_OUT
        self.text = self.metadata['text']
        self.setToolTip(self.metadata['tooltip'])
        self.arcs = []
        self.menu = None
        self.action_sign = None
        self.action_transaction = None
        self.action_contact = None
        self.action_show_member = None

        # color around ellipse
        outline_color = QColor('grey')
        outline_style = Qt.SolidLine
        outline_width = 1
        if self.status_wallet:
            outline_color = QColor('black')
            outline_width = 2
        if not self.status_member:
            outline_color = QColor('red')
            outline_style = Qt.SolidLine
        self.setPen(QPen(outline_color, outline_width, outline_style))

        # text inside ellipse
        self.text_item = QGraphicsSimpleTextItem(self)
        self.text_item.setText(self.text)
        text_color = QColor('grey')
        if self.status_wallet == NODE_STATUS_HIGHLIGHTED:
            text_color = QColor('black')
        self.text_item.setBrush(QBrush(text_color))
        # center ellipse around text
        self.setRect(
            0,
            0,
            self.text_item.boundingRect().width() * 2,
            self.text_item.boundingRect().height() * 2
        )

        #  set anchor to the center
        self.setTransform(
            QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0))
        self.setPos(x, y)
        # center text in ellipse
        self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0)

        # create gradient inside the ellipse
        gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width())
        gradient.setColorAt(0, QColor('white'))
        gradient.setColorAt(1, QColor('darkgrey'))
        self.setBrush(QBrush(gradient))

        # cursor change on hover
        self.setAcceptHoverEvents(True)
        self.setZValue(1)

    def mousePressEvent(self, event: QMouseEvent):
        """
        Click on mouse button

        :param event: mouse event
        """
        if event.button() == Qt.LeftButton:
            # trigger scene signal
            self.scene().node_clicked.emit(self.metadata)

    def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent):
        """
        Mouse enter on node zone

        :param event: scene hover event
        """
        self.setCursor(Qt.ArrowCursor)

    def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent):
        """
        Right click on node to show node menu
        Except on wallet node

        :param event: scene context menu event
        """
        #  no menu on the wallet node
        if self.status_wallet:
            return None
        # create node context menus
        self.menu = QMenu()
        # action show member
        QT_TRANSLATE_NOOP('WoT.Node', 'Informations')
        self.action_show_member = QAction(QCoreApplication.translate('WoT.Node', 'Informations'), self.scene())
        self.menu.addAction(self.action_show_member)
        self.action_show_member.triggered.connect(self.member_action)
        # action add identity as contact
        QT_TRANSLATE_NOOP('WoT.Node', 'Add as contact')
        self.action_contact = QAction(QCoreApplication.translate('WoT.Node', 'Add as contact'), self.scene())
        self.menu.addAction(self.action_contact)
        self.action_contact.triggered.connect(self.contact_action)
        # action transaction toward identity
        QT_TRANSLATE_NOOP('WoT.Node', 'Send money')
        self.action_transaction = QAction(QCoreApplication.translate('WoT.Node', 'Send money'), self.scene())
        self.menu.addAction(self.action_transaction)
        self.action_transaction.triggered.connect(self.transaction_action)
        # action sign identity
        QT_TRANSLATE_NOOP('WoT.Node', 'Certify identity')
        self.action_sign = QAction(QCoreApplication.translate('WoT.Node', 'Certify identity'), self.scene())
        self.menu.addAction(self.action_sign)
        self.action_sign.triggered.connect(self.sign_action)
        # run menu
        self.menu.exec(event.screenPos())

    def add_arc(self, arc):
        """
        Add arc to the arc list

        :param arc: Arc
        """
        self.arcs.append(arc)

    def member_action(self):
        """
        Transaction action to identity node
        """
        # trigger scene signal
        self.scene().node_member.emit(self.metadata)

    def contact_action(self):
        """
        Transaction action to identity node
        """
        # trigger scene signal
        self.scene().node_contact.emit(self.metadata)

    def sign_action(self):
        """
        Sign identity node
        """
        # trigger scene signal
        self.scene().node_signed.emit(self.metadata)

    def transaction_action(self):
        """
        Transaction action to identity node
        """
        # trigger scene signal
        self.scene().node_transaction.emit(self.metadata)
Ejemplo n.º 40
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
Ejemplo n.º 41
0
class ActiveSliceItem(QGraphicsRectItem):
    """ActiveSliceItem for the Path View"""
    def __init__(self, part_item, active_base_index):
        super(ActiveSliceItem, self).__init__(part_item)
        self._part_item = part_item
        self._getActiveTool = part_item._getActiveTool
        self._active_slice = 0
        self._low_drag_bound = 0
        self._high_drag_bound = self.part().maxBaseIdx()
        self._controller = ActiveSliceItemController(self, part_item.part())

        self._label = QGraphicsSimpleTextItem("", parent=self)
        self._label.setPos(0, -18)
        self._label.setFont(_FONT)
        self._label.setBrush(_LABEL_BRUSH)
        self._label.hide()

        self.setFlag(QGraphicsItem.ItemIsMovable)
        self.setAcceptHoverEvents(True)
        self.setZValue(styles.ZACTIVESLICEHANDLE)
        self.setRect(QRectF(0, 0, _BASE_WIDTH,\
                      self._part_item.boundingRect().height()))
        self.setPos(active_base_index * _BASE_WIDTH, 0)
        self.setBrush(_BRUSH)
        self.setPen(_PEN)

        # reuse select tool methods for other tools
        self.addSeqToolMousePress = self.selectToolMousePress
        self.addSeqToolMouseMove = self.selectToolMouseMove
        self.breakToolMousePress = self.selectToolMousePress
        self.breakToolMouseMove = self.selectToolMouseMove
        self.insertionToolMousePress = self.selectToolMousePress
        self.insertionToolMouseMove = self.selectToolMouseMove
        self.paintToolMousePress = self.selectToolMousePress
        self.paintToolMouseMove = self.selectToolMouseMove
        self.pencilToolMousePress = self.selectToolMousePress
        self.pencilToolMouseMove = self.selectToolMouseMove
        self.skipToolMousePress = self.selectToolMousePress
        self.skipToolMouseMove = self.selectToolMouseMove

    # end def

    ### SLOTS ###
    def strandChangedSlot(self, sender, vh):
        pass

    # end def

    def updateRectSlot(self, part):
        bw = _BASE_WIDTH
        new_rect = QRectF(0, 0, bw,\
                    self._part_item.virtualHelixBoundingRect().height())
        if new_rect != self.rect():
            self.setRect(new_rect)
        self._hideIfEmptySelection()
        self.updateIndexSlot(part, part.activeBaseIndex())
        return new_rect

    # end def

    def updateIndexSlot(self, part, base_index):
        """The slot that receives active slice changed notifications from
        the part and changes the receiver to reflect the part"""
        label = self._label
        bw = _BASE_WIDTH
        bi = util.clamp(int(base_index), 0, self.part().maxBaseIdx())
        self.setPos(bi * bw, -styles.PATH_HELIX_PADDING)
        self._active_slice = bi
        if label:
            label.setText("%d" % bi)
            label.setX((bw - label.boundingRect().width()) / 2)

    # end def

    ### ACCESSORS ###
    def activeBaseIndex(self):
        return self.part().activeBaseIndex()

    # end def

    def part(self):
        return self._part_item.part()

    # end def

    def partItem(self):
        return self._part_item

    # end def

    ### PUBLIC METHODS FOR DRAWING / LAYOUT ###
    def removed(self):
        scene = self.scene()
        scene.removeItem(self._label)
        scene.removeItem(self)
        self._part_item = None
        self._label = None
        self._controller.disconnectSignals()
        self.controller = None

    # end def

    def resetBounds(self):
        """Call after resizing virtualhelix canvas."""
        self._high_drag_bound = self.part().maxBaseIdx()

    # end def

    ### PRIVATE SUPPORT METHODS ###
    def _hideIfEmptySelection(self):
        vis = self.part().numberOfVirtualHelices() > 0
        self.setVisible(vis)
        self._label.setVisible(vis)

    # end def

    def _setActiveBaseIndex(self, base_index):
        self.part().setActiveBaseIndex(base_index)

    # end def

    ### EVENT HANDLERS ###
    def hoverEnterEvent(self, event):
        self.setCursor(Qt.OpenHandCursor)
        self._part_item.updateStatusBar("%d" % self.part().activeBaseIndex())
        QGraphicsItem.hoverEnterEvent(self, event)

    # end def

    def hoverLeaveEvent(self, event):
        self.setCursor(Qt.ArrowCursor)
        self._part_item.updateStatusBar("")
        QGraphicsItem.hoverLeaveEvent(self, event)

    # end def

    def mousePressEvent(self, event):
        """
        Parses a mousePressEvent, calling the approproate tool method as
        necessary. Stores _move_idx for future comparison.
        """
        if event.button() != Qt.LeftButton:
            event.ignore()
            QGraphicsItem.mousePressEvent(self, event)
            return
        self.scene().views()[0].addToPressList(self)
        self._move_idx = int(floor((self.x() + event.pos().x()) / _BASE_WIDTH))
        tool_method_name = self._getActiveTool().methodPrefix() + "MousePress"
        if hasattr(self, tool_method_name):  # if the tool method exists
            modifiers = event.modifiers()
            getattr(self, tool_method_name)(modifiers)  # call tool method

    def mouseMoveEvent(self, event):
        """
        Parses a mouseMoveEvent, calling the approproate tool method as
        necessary. Updates _move_idx if it changed.
        """
        tool_method_name = self._getActiveTool().methodPrefix() + "MouseMove"
        if hasattr(self, tool_method_name):  # if the tool method exists
            idx = int(floor((self.x() + event.pos().x()) / _BASE_WIDTH))
            if idx != self._move_idx:  # did we actually move?
                modifiers = event.modifiers()
                self._move_idx = idx
                getattr(self, tool_method_name)(modifiers,
                                                idx)  # call tool method

    def customMouseRelease(self, event):
        """
        Parses a mouseReleaseEvent, calling the approproate tool method as
        necessary. Deletes _move_idx if necessary.
        """
        tool_method_name = self._getActiveTool().methodPrefix(
        ) + "MouseRelease"
        if hasattr(self, tool_method_name):  # if the tool method exists
            modifiers = event.modifiers()
            x = event.pos().x()
            getattr(self, tool_method_name)(modifiers, x)  # call tool method
        if hasattr(self, '_move_idx'):
            del self._move_idx

    ### TOOL METHODS ###
    def selectToolMousePress(self, modifiers):
        """
        Set the allowed drag bounds for use by selectToolMouseMove.
        """
        if (modifiers & Qt.AltModifier) and (modifiers & Qt.ShiftModifier):
            self.part().undoStack().beginMacro("Auto-drag Scaffold(s)")
            for vh in self.part().getVirtualHelices():
                # SCAFFOLD
                # resize 3' first
                for strand in vh.scaffoldStrandSet():
                    idx5p = strand.idx5Prime()
                    idx3p = strand.idx3Prime()
                    if not strand.hasXoverAt(idx3p):
                        lo, hi = strand.getResizeBounds(idx3p)
                        if strand.isDrawn5to3():
                            strand.resize((idx5p, hi))
                        else:
                            strand.resize((lo, idx5p))
                # resize 5' second
                for strand in vh.scaffoldStrandSet():
                    idx5p = strand.idx5Prime()
                    idx3p = strand.idx3Prime()
                    if not strand.hasXoverAt(idx5p):
                        lo, hi = strand.getResizeBounds(idx5p)
                        if strand.isDrawn5to3():
                            strand.resize((lo, idx3p))
                        else:
                            strand.resize((idx3p, hi))
                # STAPLE
                # resize 3' first
                for strand in vh.stapleStrandSet():
                    idx5p = strand.idx5Prime()
                    idx3p = strand.idx3Prime()
                    if not strand.hasXoverAt(idx3p):
                        lo, hi = strand.getResizeBounds(idx3p)
                        if strand.isDrawn5to3():
                            strand.resize((idx5p, hi))
                        else:
                            strand.resize((lo, idx5p))
                # resize 5' second
                for strand in vh.stapleStrandSet():
                    idx5p = strand.idx5Prime()
                    idx3p = strand.idx3Prime()
                    if not strand.hasXoverAt(idx3p):
                        lo, hi = strand.getResizeBounds(idx5p)
                        if strand.isDrawn5to3():
                            strand.resize((lo, idx3p))
                        else:
                            strand.resize((idx3p, hi))

            self.part().undoStack().endMacro()

    # end def

    def selectToolMouseMove(self, modifiers, idx):
        """
        Given a new index (pre-validated as different from the prev index),
        calculate the new x coordinate for self, move there, and notify the
        parent strandItem to redraw its horizontal line.
        """
        idx = util.clamp(idx, self._low_drag_bound, self._high_drag_bound)
        x = int(idx * _BASE_WIDTH)
        self.setPos(x, self.y())
        self.updateIndexSlot(None, idx)
        self._setActiveBaseIndex(idx)
        self._part_item.updateStatusBar("%d" % self.part().activeBaseIndex())
Ejemplo n.º 42
0
    def mainFunc(self, playing, scriptList, scriptPos):

        if self.inputImg is not None:
            self.outputImg = self.inputImg

            pass_ = 0

            fx = 1.0
            fy = 1.0
            offset_x = 0.0
            offset_y = 0.0
            for i in range(scriptPos):
                widget = scriptList[i][1]
                if widget.objectName() == 'resize':
                    fx *= widget.dblFx.value()
                    fy *= widget.dblFx.value()

                pass_ += widget.pass_
                for item in widget.graphicsItems:
                    try:
                        # ~ print('item.rect() ', item.rect())
                        if fx != 1.0:
                            item.setScale(1 / fx)
                        # ~ if fy != 1.0:
                        # ~ item.setHeight(item.height()/fy)
                        if offset_x:
                            item.setX((item.x() + offset_x) / fx)
                            # ~ item.setX( (item.x() + offset_x)/1.0 )
                            # ~ print('offset_x: ', offset_x, '  fx: ', fx)
                        if offset_y:
                            item.setY((item.y() + offset_y) / fy)
                            # ~ item.setY( (item.y() + offset_y)/1.0 )
                        self.graphicsView.scene().addItem(item)
                        item.setZValue(1)
                    except RuntimeError as e:
                        print(time.time(),
                              'Runtime Error show_graphics_items mainFunc')
                        print(e)

                if widget.objectName() == 'circles':
                    if widget.chkCrop.isChecked():
                        try:
                            circle = widget.graphicsItems[0]
                            # ~ circle = item
                            offset_x = circle.x()
                            offset_x = circle.rect().left()
                            offset_y = circle.y()
                            offset_y = circle.rect().top()
                            # ~ print('offer setter ', offset_x)
                        except IndexError as e:
                            print(e)
            if self.chkShowPass.isChecked():
                # ~ h = self.graphicsView.scene().height()
                # ~ w = self.graphicsView.scene().width()
                h = self.inputImg.shape[0]
                w = self.inputImg.shape[1]

                # ~ sfh = float(h)/float(self.graphicsView.minimumHeight())
                # ~ sfw = float(w)/float(self.graphicsView.minimumWidth())
                # ~ sf = min(sfh,sfw)

                outlineRect = QGraphicsRectItem(0, 0, w, h)
                outlineLine = QGraphicsLineItem(0, h, w, 0)

                font = QFont("DejaVu Sans", 45)

                if pass_ == scriptPos:
                    # the overall result is pass
                    text = 'PASS'
                    pen = QPen(QColor(0, 255, 0), 8)  #green for pass
                    brush = QBrush(QColor(0, 255, 0))

                else:
                    # overall result is fail
                    text = 'FAIL'
                    pen = QPen(QColor(255, 0, 0), 8)  #red for fail
                    brush = QBrush(QColor(255, 0, 0))

                    outlineLine.setPen(pen)
                    self.graphicsView.scene().addItem(outlineLine)
                    outlineLine.setZValue(1)

                outlineRect.setPen(pen)
                self.graphicsView.scene().addItem(outlineRect)
                textItem = QGraphicsSimpleTextItem(text, )
                textItem.setFont(font)
                textItem.setBrush(brush)
                textItem.setPos(w / 10.0, h / 10.0)
                self.graphicsView.scene().addItem(textItem)
                textItem.setZValue(1)
Ejemplo n.º 43
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()