def draw_word_boxes(self, word_boxes: list) -> None:
        """Sets up and draws translated words and their corresponding frames

        :param word_boxes: list of WordBox namedtuples, each representing a word and frame to be drawn.
                           ex: [WordBox('word'=str, 'geometry'=[(int, int)], WordBox('word'=str, 'geometry'=[(int, int)])

        """

        for wPoly in self.__word_polygons:
            self.__scene.removeItem(wPoly[0])
            self.__scene.removeItem(wPoly[1])

        self.__word_polygons = []

        for word_box in word_boxes:
            points = list(map(lambda x: QPoint(x[0], x[1]), word_box.geometry))

            text = QGraphicsTextItem(word_box.word)
            text.setOpacity(0)
            text.setAcceptHoverEvents(False)

            font = QFont()
            font.setPixelSize(abs(points[0].y() - points[3].y()))
            text.setFont(font)

            w = text.boundingRect().width()
            h = text.boundingRect().height()
            text.setPos(
                points[0].x() + abs(points[0].x() - points[1].x()) / 2 - w / 2,
                points[0].y() + abs(points[0].y() - points[3].y()) / 2 - h / 2)
            frame = WordPolygon(QPolygonF(QPolygon(points)), text)

            self.__word_polygons.append([text, frame])
            self.__scene.addItem(frame)
            self.__scene.addItem(text)
    def texting(self):
        # image = self.image.copy()
        # cv2.putText(image,
        #             self.ui.textEdit_edit.toPlainText(),
        #             (10, 10),
        #             cv2.FONT_HERSHEY_SIMPLEX,
        #             0.6, (0, 0, 0), lineType=cv2.LINE_AA)
        # qpixmap = mat2qpixmap(image)
        # self.scene_edit.clear()
        # self.scene_edit.addPixmap(qpixmap)
        # self.scene_edit.update()

        text = self.ui.textEdit_edit.toPlainText()

        self.scene_edit.clear()
        self.scene_edit.addPixmap(self.qPixmap)
        qText = QGraphicsTextItem()
        qText.setDefaultTextColor(QColor(0, 0, 0))
        qText.setPlainText(text)
        qText.setFont(self.font)

        qPixmapWidth = self.qPixmap.width()
        qTextWidth = qText.boundingRect().width()
        qPixmapHeight = self.qPixmap.height()
        qTextHeigt = qText.boundingRect().height()

        posX = (qPixmapWidth - qTextWidth) / 2 + self.posX_default
        posY = (qPixmapHeight - qTextHeigt) / 2 + self.posY_default

        qText.setPos(posX, posY)

        self.scene_edit.addItem(qText)
        self.scene_edit.update()
Exemple #3
0
 def update_items(self):
     rect_cls = QGraphicsRectItem
     self.item = rect_cls(0, 0, self.width, self.row_h)
     seq_width = 0
     nopen = QPen(Qt.NoPen)
     font = QFont(self.ftype, self.fsize)
     for i, letter in enumerate(self.seq):
         width = self.col_w
         rectitem = rect_cls(0, 0, width, self.row_h, parent=self.item)
         rectitem.setX(seq_width)  # to give correct X to children item
         rectitem.setBrush(self.bg_col[letter])
         rectitem.setPen(nopen)
         # write letter if enough space
         if width >= self.fsize:
             text = None
             if self.style == "codon":
                 text = QGraphicsTextItem(parent=rectitem)
                 text.setHtml(self.get_html(i, self.fg_col[letter]))
             else:
                 text = QGraphicsSimpleTextItem(letter, parent=rectitem)
                 text.setBrush(QBrush(QColor(self.fg_col[letter])))
             text.setFont(font)
             # Center text according to rectitem size
             txtw = text.boundingRect().width()
             txth = text.boundingRect().height()
             text.setPos((width - txtw) / 2, (self.row_h - txth) / 2)
         seq_width += width
     self.width = seq_width
Exemple #4
0
    def createImage(self, transform):
        if self.type == DemoTextItem.DYNAMIC_TEXT:
            return None

        sx = min(transform.m11(), transform.m22())
        sy = max(transform.m22(), sx)

        textItem = QGraphicsTextItem()
        textItem.setHtml(self.text)
        textItem.setTextWidth(self.textWidth)
        textItem.setFont(self.font)
        textItem.setDefaultTextColor(self.textColor)
        textItem.document().setDocumentMargin(2)

        w = textItem.boundingRect().width()
        h = textItem.boundingRect().height()
        image = QImage(int(w * sx), int(h * sy),
                QImage.Format_ARGB32_Premultiplied)
        image.fill(QColor(0, 0, 0, 0).rgba())
        painter = QPainter(image)
        painter.scale(sx, sy)
        style = QStyleOptionGraphicsItem()
        textItem.paint(painter, style, None)

        return image
Exemple #5
0
    def createImage(self, transform):
        if self.type == DemoTextItem.DYNAMIC_TEXT:
            return None

        sx = min(transform.m11(), transform.m22())
        sy = max(transform.m22(), sx)

        textItem = QGraphicsTextItem()
        textItem.setHtml(self.text)
        textItem.setTextWidth(self.textWidth)
        textItem.setFont(self.font)
        textItem.setDefaultTextColor(self.textColor)
        textItem.document().setDocumentMargin(2)

        w = textItem.boundingRect().width()
        h = textItem.boundingRect().height()
        image = QImage(int(w * sx), int(h * sy),
                QImage.Format_ARGB32_Premultiplied)
        image.fill(QColor(0, 0, 0, 0).rgba())
        painter = QPainter(image)
        painter.scale(sx, sy)
        style = QStyleOptionGraphicsItem()
        textItem.paint(painter, style, None)

        return image
Exemple #6
0
class MenuButton(QGraphicsRectItem):
    def __init__(self, name, height=200, width=50, parent=None):
        '''name: str '''
        super().__init__(parent)
        # Set locked atribute
        self.locked = False

        # create my signal
        self.s = ButtonSignal()

        # draw the rect
        self.setRect(0, 0, height, width)

        # change color of rect
        brush = QBrush()
        brush.setStyle(Qt.SolidPattern)
        brush.setColor(Qt.darkCyan)
        self.setBrush(brush)

        # draw the text
        self.text = QGraphicsTextItem(name, self)
        x_pos = self.rect().width() / 2 - self.text.boundingRect().width() / 2
        y_pos = self.rect().height() / 2 - self.text.boundingRect().height() / 2
        self.text.setPos(x_pos, y_pos)

        # allow responding to hover events
        self.setAcceptHoverEvents(True)

    def mousePressEvent(self, event):
        if not self.locked:
            self.s.clicked.emit()

    def hoverEnterEvent(self, event):
        '''event: QGraphicsSceneHoverEvent '''
        # change color to cyan
        brush = QBrush()
        brush.setStyle(Qt.SolidPattern)
        brush.setColor(Qt.cyan)
        self.setBrush(brush)

    def hoverLeaveEvent(self, event):
        '''event: QGraphicsSceneHoverEvent '''
        # change color to dark cyan
        brush = QBrush()
        brush.setStyle(Qt.SolidPattern)
        brush.setColor(Qt.darkCyan)
        self.setBrush(brush)

    def unlock(self):
        self.setOpacity(1)
        self.locked = False

    def lock(self):
        self.setOpacity(0.3)
        self.locked = True
Exemple #7
0
    def printAttributes(self, background, border, text):
        """
        Prints the attributes of the node
        The attributes are a key, value pair

        :param background: background color of the node
        :param border: border color for the node
        :param text: text color for the node
        """
        y = self.y() + self.headerHeight
        x = self.x()

        self.attributesHeight = 0

        for k, v in self.node.attributes.items():
            key = QGraphicsTextItem()
            key.setFont(Configuration.font)
            key.setDefaultTextColor(QColor(text))
            key.setTextWidth(100)
            key.setPlainText(k)
            keyHeight = int(key.boundingRect().height() / 20 + 0.5) * 20

            value = QGraphicsTextItem()
            value.setFont(Configuration.font)
            value.setDefaultTextColor(QColor(text))
            value.setTextWidth(100)
            value.setPlainText(v)
            valueHeight = int(value.boundingRect().height() / 20 + 0.5) * 20

            height = valueHeight if valueHeight > keyHeight else keyHeight

            keyRect = QGraphicsRectItem()
            keyRect.setRect(x, y, 100, height)
            valueRect = QGraphicsRectItem()
            valueRect.setRect(x + 100, y, 100, height)

            keyRect.setBrush(QBrush(QColor(background)))
            valueRect.setBrush(QBrush(QColor(background)))

            keyRect.setPen(QPen(QColor(border), 2))
            valueRect.setPen(QPen(QColor(border), 2))

            key.setPos(x, y - 2)
            value.setPos(x + 100, y - 2)

            self.attributes.addToGroup(keyRect)
            self.attributes.addToGroup(valueRect)
            self.attributes.addToGroup(key)
            self.attributes.addToGroup(value)

            y = y + height
            self.attributesHeight += height

        self.addToGroup(self.attributes)
Exemple #8
0
class ActionItem(GraphicsItem):
    def __init__(self, model_item: SimulatorItem, parent=None):
        super().__init__(model_item=model_item, parent=parent)

        self.setFlag(QGraphicsTextItem.ItemIsPanel, True)

        self.text = QGraphicsTextItem(self)
        self.text.setFont(GraphicsItem.font)

    def update_flags(self):
        if self.scene().mode == 0:
            self.set_flags(is_selectable=True,
                           is_movable=True,
                           accept_hover_events=True,
                           accept_drops=True)

    def update_position(self, x_pos, y_pos):
        self.setPos(x_pos, y_pos)
        start_x = (self.scene().items_width() - self.labels_width()) / 2
        self.number.setPos(start_x, 0)
        start_x += self.number.boundingRect().width()
        self.text.setPos(start_x, 0)

        width = self.scene().items_width()
        self.prepareGeometryChange()
        self.bounding_rect = QRectF(0, 0, width,
                                    self.childrenBoundingRect().height() + 5)
        #super().update_position(x_pos, y_pos)

    def labels_width(self):
        width = self.number.boundingRect().width()
        #width += 5
        width += self.text.boundingRect().width()
        return width
Exemple #9
0
class MyRect(QGraphicsRectItem):
    def __init__(self, parent=None):
        super(MyRect, self).__init__(parent)

        self.text_item = QGraphicsTextItem('My Text Here', self)
        self.value_item = QGraphicsTextItem('My Value Here', self)
        self.text_item.setDefaultTextColor(QColor(Qt.blue))
        self.value_item.setDefaultTextColor(QColor(Qt.red))

        self.value_item.setPos(self.text_item.boundingRect().bottomLeft())

        width = max(self.text_item.boundingRect().width(),
                    self.value_item.boundingRect().width())
        height = self.text_item.boundingRect().height(
        ) + self.value_item.boundingRect().height()
        self.setRect(50, 50, width, height)
Exemple #10
0
class ActionItem(GraphicsItem):
    def __init__(self, model_item: SimulatorItem, parent=None):
        super().__init__(model_item=model_item, parent=parent)

        self.setFlag(QGraphicsTextItem.ItemIsPanel, True)

        self.text = QGraphicsTextItem(self)
        self.text.setFont(self.font)

    def update_flags(self):
        if self.scene().mode == 0:
            self.set_flags(is_selectable=True, is_movable=True, accept_hover_events=True, accept_drops=True)

    def update_position(self, x_pos, y_pos):
        self.setPos(x_pos, y_pos)
        start_x = (self.scene().items_width() - self.labels_width()) / 2
        self.number.setPos(start_x, 0)
        start_x += self.number.boundingRect().width()
        self.text.setPos(start_x, 0)

        width = self.scene().items_width()
        self.prepareGeometryChange()
        self.bounding_rect = QRectF(0, 0, width, self.childrenBoundingRect().height() + 5)

    def labels_width(self):
        width = self.number.boundingRect().width()
        width += self.text.boundingRect().width()
        return width
Exemple #11
0
class PointOfInterest:
    def __init__(self, **kwargs):
        super().__init__()
        self.location = MapPoint()
        self.__dict__.update(kwargs)
        self.text = QGraphicsTextItem()
        self.text.setHtml("<font color='{}' size='{}'>{}</font>".format(
            self.location.color.name(), 1 + self.location.size,
            '\u272a' + self.location.text))
        self.text.setZValue(2)
        self.text.setPos(self.location.x, self.location.y)

    def update_(self, scale):
        self.text.setScale(scale)
        self.text.setPos(
            self.location.x - self.text.boundingRect().width() * 0.05 * scale,
            self.location.y - self.text.boundingRect().height() / 2 * scale)
Exemple #12
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.view = VideoGraphicsView()
        self.setCentralWidget(self.view)

        self.view.videoItem.nativeSizeChanged.connect(
            self.handle_native_size_changed)

        url = QUrl(
            "https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4"
        )
        self.view.player.setMedia(QMediaContent(url))
        self.view.player.play()

        self.resize(640, 480)

        self.text_item = QGraphicsTextItem(self.view.videoItem)
        self.text_item.setHtml(
            """<div style="color: #41CD52; font-weight: bold; font-size: 20px;">Qt is awesome</div>"""
        )
        self.text_item.hide()

        self.animation = QVariantAnimation()
        self.animation.setDuration(1000)
        self.animation.setStartValue(QPointF(0.0, 0.0))
        self.animation.setEndValue(QPointF(0.0, 0.0))
        self.animation.valueChanged.connect(self.text_item.setPos)
        self.animation.finished.connect(self.start_of_start_animation)

    def handle_native_size_changed(self):
        self.start_of_start_animation()

    def start_of_start_animation(self):
        w = self.view.videoItem.size().width() - self.text_item.boundingRect(
        ).width()
        h = self.view.videoItem.size().height() - self.text_item.boundingRect(
        ).height()
        end_pos_x = random.uniform(0, w)
        end_pos_y = random.uniform(0, h)
        self.animation.setStartValue(self.animation.endValue())
        self.animation.setEndValue(QPointF(end_pos_x, end_pos_y))
        self.text_item.show()
        self.animation.start()
 def loadText(self):
     self.scene.clear()
     noImageTxt = QGraphicsTextItem()
     noImageTxt.setPlainText(
         u"Wählen Sie ein repräsentatives Luftbild aus ...")
     self.rect = noImageTxt.boundingRect()
     self.scene.addItem(noImageTxt)
     self.scene.setSceneRect(self.rect)
     self.uiRepresentativeImageView.fitInView(self.rect, Qt.KeepAspectRatio)
Exemple #14
0
class ParticipantItem(QGraphicsItem):
    def __init__(self, model_item: Participant, parent=None):
        super().__init__(parent)

        self.model_item = model_item

        self.text = QGraphicsTextItem(self)

        self.line = QGraphicsLineItem(self)
        self.line.setPen(
            QPen(Qt.darkGray, 1, Qt.DashLine, Qt.RoundCap, Qt.RoundJoin))

        self.refresh()

    def update_position(self, x_pos=-1, y_pos=-1):
        if x_pos == -1:
            x_pos = self.x_pos()

        if y_pos == -1:
            y_pos = self.line.line().y2()

        self.text.setPos(x_pos - (self.text.boundingRect().width() / 2), 0)
        self.line.setLine(x_pos, 30, x_pos, y_pos)

    def x_pos(self):
        return self.line.line().x1()

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

    def refresh(self):
        self.text.setPlainText(
            "?" if not self.model_item else self.model_item.shortname)
        if hasattr(self.model_item, "simulate") and self.model_item.simulate:
            font = QFont()
            font.setBold(True)
            self.text.setFont(font)
            self.text.setDefaultTextColor(Qt.darkGreen)
            self.line.setPen(
                QPen(Qt.darkGreen, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        else:
            self.text.setFont(QFont())
            self.text.setDefaultTextColor(constants.LINECOLOR)
            self.line.setPen(
                QPen(Qt.darkGray, 1, Qt.DashLine, Qt.RoundCap, Qt.RoundJoin))

    def boundingRect(self):
        return self.childrenBoundingRect()

    def paint(self, painter, option, widget):
        pass
Exemple #15
0
    def initUi(self):

        pos = QPointF(0, 0)

        for i in range(0, self.length):  #每一秒有1個刻度,總共 length 秒
            t1 = QGraphicsTextItem('|', self)
            t1.setDefaultTextColor(QColor(Qt.blue))
            t1.setPos(pos)

            t2 = QGraphicsTextItem('{}'.format(i + int(self.start)), self)
            t2.setDefaultTextColor(QColor(Qt.blue))
            t2.setPos(t1.boundingRect().bottomLeft() + pos)

            pos.setX(pos.x() + int(self.w / self.length))
        self.setRect(0, 0, self.w, self.h)
Exemple #16
0
    def add_text(self, text, item_list):
        items = []
        text_item = QGraphicsTextItem(text)
        text_item.setFont(ComparisionChart.arial_font)
        text_item.setPos(0,0)
        items.append(text_item)
        next_y = text_item.boundingRect().height()+5

        html = "<br />".join(sorted(item_list))
        text_item = QGraphicsTextItem()
        text_item.setHtml(html)
        text_item.setFont(ComparisionChart.font)
        text_item.setPos(5,next_y)
        items.append(text_item)
        group = self.scene.createItemGroup(items)
        return group
Exemple #17
0
class ParticipantItem(QGraphicsItem):
    def __init__(self, model_item: Participant, parent=None):
        super().__init__(parent)

        self.model_item = model_item

        self.text = QGraphicsTextItem(self)

        self.line = QGraphicsLineItem(self)
        self.line.setPen(QPen(Qt.darkGray, 1, Qt.DashLine, Qt.RoundCap, Qt.RoundJoin))

        self.refresh()

    def update_position(self, x_pos=-1, y_pos=-1):
        if x_pos == -1:
            x_pos = self.x_pos()

        if y_pos == -1:
            y_pos = self.line.line().y2()

        self.text.setPos(x_pos - (self.text.boundingRect().width() / 2), 0)
        self.line.setLine(x_pos, 30, x_pos, y_pos)

    def x_pos(self):
        return self.line.line().x1()

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

    def refresh(self):
        self.text.setPlainText("?" if not self.model_item else self.model_item.shortname)
        if hasattr(self.model_item, "simulate") and self.model_item.simulate:
            font = QFont()
            font.setBold(True)
            self.text.setFont(font)
            self.text.setDefaultTextColor(Qt.darkGreen)
            self.line.setPen(QPen(Qt.darkGreen, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        else:
            self.text.setFont(QFont())
            self.text.setDefaultTextColor(constants.LINECOLOR)
            self.line.setPen(QPen(Qt.darkGray, 1, Qt.DashLine, Qt.RoundCap, Qt.RoundJoin))

    def boundingRect(self):
        return self.childrenBoundingRect()

    def paint(self, painter, option, widget):
        pass
Exemple #18
0
def label_maker(node, label):
    """Form correctly formatted leaf label."""

    face = QGraphicsTextItem()
    face.setHtml(label)

    # Create parent RectItem with TextItem in center
    fbox = face.boundingRect()
    rect = QGraphicsRectItem(0, 0, fbox.width(), fbox.height())
    rbox = rect.boundingRect()
    face.setPos(rbox.x(), rbox.center().y() - fbox.height() / 2)

    # Remove border
    rect.setPen(QPen(QtCore.Qt.NoPen))

    # Set as parent item so DynamicItemFace can use .rect() method
    face.setParentItem(rect)

    return rect
    def update_view(self, steno_layout: StenoLayout, stroke: List[str]):
        ''' Updates the layout display for the provided layout and stroke '''

        scene = self.graphics_scene
        pen = self._scene_pen
        font = QFont(steno_layout.font) if steno_layout.font else QFont()
        # Clear all items from the scene. Could be more efficient...
        scene.clear()
        scene.setBackgroundBrush(QBrush(QColor(steno_layout.background_color)))

        for key in steno_layout.keys:
            path = LayoutDisplayView._create_key_path(steno_layout, key)
            brush = LayoutDisplayView._get_key_path_brush(key, (key.name in stroke))
            pen.setColor(QColor(key.stroke_color))

            # Add the key path before its label, then center the label
            scene.addPath(path, pen, brush)

            if key.label:
                label = QGraphicsTextItem(key.label)
                label.setFont(font)
                label.setDefaultTextColor(QColor(key.font_color))

                label_rect = label.boundingRect()
                label_rect.moveCenter(path.boundingRect().center())
                label.setPos(label_rect.x(), label_rect.y())
                scene.addItem(label)

        # Scene rects don't shrink when items are removed, so need to manually
        # set it to the current size needed by the contained items + margin
        margin = steno_layout.margin
        scene_rect = scene.itemsBoundingRect()
        scene_rect = scene_rect.marginsAdded(QMarginsF(margin, margin,
                                                       margin, margin))
        scene.setSceneRect(scene_rect)
        self.fitInView(scene.sceneRect(), Qt.KeepAspectRatio)

        self.setScene(scene)
        self.show()
Exemple #20
0
class ParticipantItem(QGraphicsItem):
    def __init__(self, model_item: Participant, parent=None):
        super().__init__(parent)

        self.model_item = model_item

        self.text = QGraphicsTextItem(self)

        self.line = QGraphicsLineItem(self)
        self.line.setPen(QPen(Qt.darkGray, 1, Qt.DashLine, Qt.RoundCap, Qt.RoundJoin))

        self.refresh()

    def update_position(self, x_pos=-1, y_pos=-1):
        if x_pos == -1:
            x_pos = self.x_pos()

        if y_pos == -1:
            y_pos = self.line.line().y2()

        self.text.setPos(x_pos - (self.text.boundingRect().width() / 2), 0)
        self.line.setLine(x_pos, 30, x_pos, y_pos)

    def x_pos(self):
        return self.line.line().x1()

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

    def refresh(self):
        self.text.setPlainText("?" if not self.model_item else self.model_item.shortname)

    def boundingRect(self):
        return self.childrenBoundingRect()

    def paint(self, painter, option, widget):
        pass
Exemple #21
0
class KeyWidget(QGraphicsRectItem):
    def __init__(self, rect: QRect, idx: int, note: str):
        super().__init__(rect.x(), rect.y(), rect.width(), rect.height())

        self.rect = rect
        self.idx = idx
        self.note = note
        self.label = None

        if note in WHITE_KEYS:
            self.setBrush(WHITE_KEY_COLOR)
            # set the label
            self.label = QGraphicsTextItem()
            self.label.setDefaultTextColor(Qt.black)
            # font = self.label.font()
            # font.setBold(True)
            # self.label.setFont(font)
            self.label.setZValue(100)
            self.label.setPlainText(note)
            self.label.setPos(
                self.rect.x() + self.rect.width() / 2 -
                self.label.boundingRect().width() / 2,
                self.rect.y() + self.rect.height() * 0.8)
        else:
            self.setBrush(Qt.black)

    def press(self, out_of_range=False):
        if out_of_range:
            self.setBrush(Qt.yellow)
        else:
            self.setBrush(Qt.gray)

    def release(self):
        if self.note in WHITE_KEYS:
            self.setBrush(WHITE_KEY_COLOR)
        else:
            self.setBrush(BLACK_KEY_COLOR)
Exemple #22
0
    def add_chart(self, text, data, eq=False):
        items = []

        text_item = QGraphicsTextItem(text)
        text_item.setFont(ComparisionChart.arial_font)
        text_item.setPos(0,0)
        items.append(text_item)
        next_y = text_item.boundingRect().height()+5
        if not data:
            text_item = QGraphicsTextItem("prazno")
            text_item.setFont(ComparisionChart.font)
            text_item.setPos(0,next_y)
            items.append(text_item)

            group = self.scene.createItemGroup(items)
            return group

        item_max = 0
        before_max = len("before")
        after_max = len("after")

        def fmt_num(number):
            return "{:.2f}".format(number)
        def fmt_num_align(number, width):
            fmt = "{:^%d.2f}" % width
            return fmt.format(number)

        for item, before, after in data:
            item_max = max(item_max, len(item))
            before_max = max(before_max, len(fmt_num(before)))
            after_max = max(after_max, len(fmt_num(after)))

        before_larger = False
        if before > after:
            before_larger = True


        item_max_s= item_max*9
        before_max_s= before_max*9
        after_max_s= after_max*9

        full_size = before_max_s+5+after_max_s
        start_chart = item_max_s+5

        for item, before, after in data:
            if before_larger:
                large = before
                small = after
            else:
                large = after
                small = before

            if not eq:
                rect_item = QGraphicsRectItem()
                old_height = 0.8*text_item.boundingRect().height()
                rect_item.setRect(start_chart,next_y, full_size,
                        old_height)
                if before_larger:
                    rect_item.setBrush(ComparisionChart.color1_brush)
                else:
                    rect_item.setBrush(ComparisionChart.color2_brush)
                rect_item.setPen(ComparisionChart.no_pen)
                items.append(rect_item)

                rect_item = QGraphicsRectItem()
                new_height = 0.4*text_item.boundingRect().height()
                rect_item.setRect(start_chart,next_y+(old_height-new_height)/2,
                        full_size*(small/large),
                        new_height)
                if before_larger:
                    rect_item.setBrush(ComparisionChart.color2_brush)
                else:
                    rect_item.setBrush(ComparisionChart.color1_brush)
                rect_item.setPen(ComparisionChart.no_pen)
                items.append(rect_item)

            text_item = QGraphicsTextItem(item)
            text_item.setFont(ComparisionChart.font)
            text_item.setPos(0, next_y)
            items.append(text_item)
            
            text_item = QGraphicsTextItem(fmt_num_align(before, before_max))
            text_item.setFont(ComparisionChart.font)
            text_item.setPos(item_max_s, next_y)
            items.append(text_item)

            text_item = QGraphicsTextItem(fmt_num_align(after, after_max))
            text_item.setFont(ComparisionChart.font)
            text_item.setPos(item_max_s+5+before_max_s, next_y)
            items.append(text_item)

            next_y+=text_item.boundingRect().height()


        #barsets = [QBarSet("previous"), QBarSet("current")]
        #cats = []
        #for i, (item, before, now) in enumerate(data):
            #print (item, before, now)
            #barsets[1].append(before)
            #barsets[0].append(now)
            #cats.append(item)
        #axis_y = QBarCategoryAxis()
        #axis_y.append(cats)
        #barseries = QHorizontalBarSeries()
        #barseries.append(barsets)
        #chart = QChart()
        #chart.addSeries(barseries)
        #chart.setTitle(text)
        #chart.setAnimationOptions(QChart.SeriesAnimations)
        #chart.setAxisY(axis_y, barseries)
        #chart.setPos(0, next_y)
        #chart.setPreferredWidth(width)
        #chart.setPreferredHeight(500)
        ##chart.setSize(200,200)
        ##print ("SIZE:", chart.size().toSize().width(),
                ##chart.size().toSize().height())
        ##print ("CHART:", chart.boundingRect().width(),
                ##chart.boundingRect().height())
        #items.append(chart)

        group = self.scene.createItemGroup(items)
        return group
Exemple #23
0
class RuleConditionItem(GraphicsItem):
    def __init__(self, model_item: SimulatorRuleCondition, parent=None):
        assert isinstance(model_item, SimulatorRuleCondition)
        super().__init__(model_item=model_item, parent=parent)

        self.number.setFont(self.font_bold)

        self.text = QGraphicsTextItem(self)
        self.text.setPlainText(self.model_item.type.value)
        self.text.setFont(self.font_bold)

        self.desc = QGraphicsTextItem(self)
        self.desc.setFont(self.font)

    def update_flags(self):
        if self.scene().mode == 0:
            self.set_flags(is_selectable=True, accept_hover_events=True, accept_drops=True)
        else:
            self.set_flags(is_selectable=True, accept_hover_events=True)

    def labels_width(self):
        return max(self.number.boundingRect().width() + self.text.boundingRect().width(),
                   self.desc.boundingRect().width())

    def refresh(self):
        if len(self.model_item.condition):
            if len(self.model_item.condition) > 20:
                self.desc.setPlainText(self.model_item.condition[:20] + "...")
            else:
                self.desc.setPlainText(self.model_item.condition)
        elif self.model_item.type != ConditionType.ELSE:
            self.desc.setPlainText("<Condition>")

    def update_position(self, x_pos, y_pos):
        self.setPos(x_pos, y_pos)

        start_y = 0
        start_x = ((self.scene().items_width() + 40) - (
                    self.number.boundingRect().width() + self.text.boundingRect().width())) / 2
        self.number.setPos(start_x, start_y)
        start_x += self.number.boundingRect().width()
        self.text.setPos(start_x, start_y)
        start_y += round(self.number.boundingRect().height())
        start_x = ((self.scene().items_width() + 40) - self.desc.boundingRect().width()) / 2
        self.desc.setPos(start_x, start_y)

        if self.model_item.type != ConditionType.ELSE:
            start_y += round(self.desc.boundingRect().height())

        start_y += 5

        for child in self.get_scene_children():
            child.update_position(20, start_y)
            start_y += round(child.boundingRect().height())

        width = self.scene().items_width()
        self.prepareGeometryChange()
        self.bounding_rect = QRectF(0, 0, width + 40, self.childrenBoundingRect().height() + 5)

    def update_drop_indicator(self, pos):
        rect = self.boundingRect()

        if pos.y() - rect.top() < rect.height() / 3:
            self.drop_indicator_position = QAbstractItemView.AboveItem
        elif rect.bottom() - pos.y() < rect.height() / 3:
            self.drop_indicator_position = QAbstractItemView.BelowItem
        else:
            self.drop_indicator_position = QAbstractItemView.OnItem

        self.update()

    def paint(self, painter, option, widget):
        if self.scene().mode == 1:
            self.setOpacity(1 if self.model_item.logging_active else 0.3)

        painter.setOpacity(constants.SELECTION_OPACITY)

        if self.hover_active or self.isSelected():
            painter.setBrush(constants.SELECTION_COLOR)
        elif not self.is_valid():
            painter.setBrush(QColor(255, 0, 0, 150))
        else:
            painter.setBrush(QColor.fromRgb(204, 204, 204, 255))

        height = self.number.boundingRect().height()

        if self.model_item.type != ConditionType.ELSE:
            height += self.desc.boundingRect().height()

        painter.drawRect(QRectF(0, 0, self.boundingRect().width(), height))

        painter.setBrush(Qt.NoBrush)
        painter.drawRect(self.boundingRect())

        if self.drag_over:
            self.paint_drop_indicator(painter)

    def paint_drop_indicator(self, painter):
        painter.setPen(QPen(Qt.darkRed, 2, Qt.SolidLine))
        painter.setBrush(Qt.NoBrush)
        rect = self.boundingRect()

        if self.drop_indicator_position == QAbstractItemView.AboveItem:
            painter.drawLine(QLineF(rect.topLeft(), rect.topRight()))
        elif self.drop_indicator_position == QAbstractItemView.OnItem:
            painter.drawRect(rect)
        else:
            painter.drawLine(QLineF(rect.bottomLeft(), rect.bottomRight()))
Exemple #24
0
class BlockItem(QGraphicsPixmapItem):
    def __init__(self, trnsysType, parent, **kwargs):
        super().__init__(None)

        self.logger = parent.logger

        self.w = 120
        self.h = 120
        self.parent = parent
        self.id = self.parent.parent().idGen.getID()
        self.propertyFile = []

        if "displayName" in kwargs:
            self.displayName = kwargs["displayName"]
        else:
            self.displayName = trnsysType + "_" + str(self.id)

        if "loadedBlock" not in kwargs:
            self.parent.parent().trnsysObj.append(self)

        self.inputs = []
        self.outputs = []

        # Export related:
        self.name = trnsysType
        self.trnsysId = self.parent.parent().idGen.getTrnsysID()

        # Transform related
        self.flippedV = False
        self.flippedH = False
        self.rotationN = 0
        self.flippedHInt = -1
        self.flippedVInt = -1

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

        # To set flags of this item
        self.setFlags(self.ItemIsSelectable | self.ItemIsMovable)
        self.setFlag(self.ItemSendsScenePositionChanges, True)
        self.setCursor(QCursor(QtCore.Qt.PointingHandCursor))

        self.label = QGraphicsTextItem(self.displayName, self)
        self.label.setVisible(False)

        if self.name == "Bvi":
            self.inputs.append(_cspi.createSinglePipePortItem("i", 0, self))
            self.outputs.append(_cspi.createSinglePipePortItem("o", 2, self))

        if self.name == "StorageTank":
            # Inputs get appended in ConfigStorage
            pass

        self.logger.debug("Block name is " + str(self.name))

        # Update size for generic block:
        if self.name == "Bvi":
            self.changeSize()

        # Experimental, used for detecting genereated blocks attached to storage ports
        self.inFirstRow = False

        # Undo framework related
        self.oldPos = None

        self.origOutputsPos = None
        self.origInputsPos = None

    def _getImageAccessor(self) -> _tp.Optional[_img.ImageAccessor]:
        if type(self) == BlockItem:
            raise AssertionError(
                "`BlockItem' cannot be instantiated directly.")

        currentClassName = BlockItem.__name__
        currentMethodName = f"{currentClassName}.{BlockItem._getImageAccessor.__name__}"

        message = (
            f"{currentMethodName} has been called. However, this method should not be called directly but must\n"
            f"implemented in a child class. This means that a) someone instantiated `{currentClassName}` directly\n"
            f"or b) a child class of it doesn't implement `{currentMethodName}`. Either way that's an\n"
            f"unrecoverable error and therefore the program will be terminated now. Please do get in touch with\n"
            f"the developers if you've encountered this error. Thanks.")

        exception = AssertionError(message)

        # I've seen exception messages mysteriously swallowed that's why we're logging the message here, too.
        self.logger.error(message, exc_info=exception, stack_info=True)

        raise exception

    def addTree(self):
        pass

    # Setter functions
    def setParent(self, p):
        self.parent = p

        if self not in self.parent.parent().trnsysObj:
            self.parent.parent().trnsysObj.append(self)
            # self.logger.debug("trnsysObj are " + str(self.parent.parent().trnsysObj))

    def setId(self, newId):
        self.id = newId

    def setName(self, newName):
        self.displayName = newName
        self.label.setPlainText(newName)

    # Interaction related
    def contextMenuEvent(self, event):
        menu = QMenu()

        a1 = menu.addAction("Launch NotePad++")
        a1.triggered.connect(self.launchNotepadFile)

        rr = _img.ROTATE_TO_RIGHT_PNG.icon()
        a2 = menu.addAction(rr, "Rotate Block clockwise")
        a2.triggered.connect(self.rotateBlockCW)

        ll = _img.ROTATE_LEFT_PNG.icon()
        a3 = menu.addAction(ll, "Rotate Block counter-clockwise")
        a3.triggered.connect(self.rotateBlockCCW)

        a4 = menu.addAction("Reset Rotation")
        a4.triggered.connect(self.resetRotation)

        b1 = menu.addAction("Print Rotation")
        b1.triggered.connect(self.printRotation)

        c1 = menu.addAction("Delete this Block")
        c1.triggered.connect(self.deleteBlockCom)

        menu.exec_(event.screenPos())

    def launchNotepadFile(self):
        self.logger.debug("Launching notpad")
        global FilePath
        os.system("start notepad++ " + FilePath)

    def mouseDoubleClickEvent(self, event):
        if hasattr(self, "isTempering"):
            self.parent.parent().showTVentilDlg(self)
        elif self.name == "Pump":
            self.parent.parent().showPumpDlg(self)
        elif self.name == "TeePiece" or self.name == "WTap_main":
            self.parent.parent().showBlockDlg(self)
        elif self.name in ["SPCnr", "DPCnr", "DPTee"]:
            self.parent.parent().showDoublePipeBlockDlg(self)
        else:
            self.parent.parent().showBlockDlg(self)
            if len(self.propertyFile) > 0:
                for files in self.propertyFile:
                    os.startfile(files, "open")

    def mouseReleaseEvent(self, event):
        # self.logger.debug("Released mouse over block")
        if self.oldPos is None:
            self.logger.debug("For Undo Framework: oldPos is None")
        else:
            if self.scenePos() != self.oldPos:
                self.logger.debug("Block was dragged")
                self.logger.debug("Old pos is" + str(self.oldPos))
                command = MoveCommand(self, self.oldPos, "Move BlockItem")
                self.parent.parent().parent().undoStack.push(command)
                self.oldPos = self.scenePos()

        super(BlockItem, self).mouseReleaseEvent(event)

    # Transform related
    def changeSize(self):
        self._positionLabel()

        w, h = self._getCappedWithAndHeight()

        if self.name == "Bvi":
            delta = 4

            self.inputs[0].setPos(
                -2 * delta + 4 * self.flippedH * delta + self.flippedH * w,
                h / 3)
            self.outputs[0].setPos(
                -2 * delta + 4 * self.flippedH * delta + self.flippedH * w,
                2 * h / 3)
            self.inputs[0].side = 0 + 2 * self.flippedH
            self.outputs[0].side = 0 + 2 * self.flippedH

    def _positionLabel(self):
        width, height = self._getCappedWithAndHeight()
        rect = self.label.boundingRect()
        labelWidth, lableHeight = rect.width(), rect.height()
        labelPosX = (height - labelWidth) / 2
        self.label.setPos(labelPosX, width)

    def _getCappedWithAndHeight(self):
        width = self.w
        height = self.h
        if height < 20:
            height = 20
        if width < 40:
            width = 40
        return width, height

    def updateFlipStateH(self, state):
        self.flippedH = bool(state)

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

        self.flippedHInt = 1 if self.flippedH else -1

        if self.flippedH:
            for i in range(0, len(self.inputs)):
                distanceToMirrorAxis = self.w / 2.0 - self.origInputsPos[i][0]
                self.inputs[i].setPos(
                    self.origInputsPos[i][0] + 2.0 * distanceToMirrorAxis,
                    self.inputs[i].pos().y(),
                )

            for i in range(0, len(self.outputs)):
                distanceToMirrorAxis = self.w / 2.0 - self.origOutputsPos[i][0]
                self.outputs[i].setPos(
                    self.origOutputsPos[i][0] + 2.0 * distanceToMirrorAxis,
                    self.outputs[i].pos().y(),
                )

        else:
            for i in range(0, len(self.inputs)):
                self.inputs[i].setPos(self.origInputsPos[i][0],
                                      self.inputs[i].pos().y())

            for i in range(0, len(self.outputs)):
                self.outputs[i].setPos(self.origOutputsPos[i][0],
                                       self.outputs[i].pos().y())

    def updateFlipStateV(self, state):
        self.flippedV = bool(state)

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

        self.flippedVInt = 1 if self.flippedV else -1

        if self.flippedV:
            for i in range(0, len(self.inputs)):
                distanceToMirrorAxis = self.h / 2.0 - self.origInputsPos[i][1]
                self.inputs[i].setPos(
                    self.inputs[i].pos().x(),
                    self.origInputsPos[i][1] + 2.0 * distanceToMirrorAxis,
                )

            for i in range(0, len(self.outputs)):
                distanceToMirrorAxis = self.h / 2.0 - self.origOutputsPos[i][1]
                self.outputs[i].setPos(
                    self.outputs[i].pos().x(),
                    self.origOutputsPos[i][1] + 2.0 * distanceToMirrorAxis,
                )

        else:
            for i in range(0, len(self.inputs)):
                self.inputs[i].setPos(self.inputs[i].pos().x(),
                                      self.origInputsPos[i][1])

            for i in range(0, len(self.outputs)):
                self.outputs[i].setPos(self.outputs[i].pos().x(),
                                       self.origOutputsPos[i][1])

    def updateSidesFlippedH(self):
        if self.rotationN % 2 == 0:
            for p in self.inputs:
                if p.side == 0 or p.side == 2:
                    self.updateSide(p, 2)
            for p in self.outputs:
                if p.side == 0 or p.side == 2:
                    self.updateSide(p, 2)
        if self.rotationN % 2 == 1:
            for p in self.inputs:
                if p.side == 1 or p.side == 3:
                    self.updateSide(p, 2)
            for p in self.outputs:
                if p.side == 1 or p.side == 3:
                    self.updateSide(p, 2)

    def updateSidesFlippedV(self):
        if self.rotationN % 2 == 1:
            for p in self.inputs:
                if p.side == 0 or p.side == 2:
                    self.updateSide(p, 2)
            for p in self.outputs:
                if p.side == 0 or p.side == 2:
                    self.updateSide(p, 2)
        if self.rotationN % 2 == 0:
            for p in self.inputs:
                if p.side == 1 or p.side == 3:
                    self.updateSide(p, 2)
            for p in self.outputs:
                if p.side == 1 or p.side == 3:
                    self.updateSide(p, 2)

    def updateSide(self, port, n):
        port.side = (port.side + n) % 4
        # self.logger.debug("Port side is " + str(port.side))

    def rotateBlockCW(self):
        # Rotate block clockwise
        # self.setTransformOriginPoint(50, 50)
        # self.setTransformOriginPoint(self.w/2, self.h/2)
        self.setTransformOriginPoint(0, 0)
        self.setRotation((self.rotationN + 1) * 90)
        self.label.setRotation(-(self.rotationN + 1) * 90)
        self.rotationN += 1
        self.logger.debug("rotated by " + str(self.rotationN))

        for p in self.inputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, 1)

        for p in self.outputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, 1)

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

    def rotateBlockToN(self, n):
        if n > 0:
            while self.rotationN != n:
                self.rotateBlockCW()
        if n < 0:
            while self.rotationN != n:
                self.rotateBlockCCW()

    def rotateBlockCCW(self):
        # Rotate block clockwise
        # self.setTransformOriginPoint(50, 50)
        self.setTransformOriginPoint(0, 0)
        self.setRotation((self.rotationN - 1) * 90)
        self.label.setRotation(-(self.rotationN - 1) * 90)
        self.rotationN -= 1
        self.logger.debug("rotated by " + str(self.rotationN))

        for p in self.inputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, -1)

        for p in self.outputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, -1)

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

    def resetRotation(self):
        self.logger.debug("Resetting rotation...")
        self.setRotation(0)
        self.label.setRotation(0)

        for p in self.inputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, -self.rotationN)
            # self.logger.debug("Portside of port " + str(p) + " is " + str(p.portSide))

        for p in self.outputs:
            p.itemChange(27, p.scenePos())
            self.updateSide(p, -self.rotationN)
            # self.logger.debug("Portside of port " + str(p) + " is " + str(p.portSide))

        self.rotationN = 0

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

    def printRotation(self):
        self.logger.debug("Rotation is " + str(self.rotationN))

    # Deletion related
    def deleteConns(self):

        for p in self.inputs:
            while len(p.connectionList) > 0:
                p.connectionList[0].deleteConn()

        for p in self.outputs:
            while len(p.connectionList) > 0:
                p.connectionList[0].deleteConn()

    def deleteBlock(self):
        self.parent.parent().trnsysObj.remove(self)
        self.parent.scene().removeItem(self)
        widgetToRemove = self.parent.parent().findChild(
            QTreeView, self.displayName + "Tree")
        if widgetToRemove:
            widgetToRemove.hide()

    def deleteBlockCom(self):
        self.parent.deleteBlockCom(self)

    def getConnections(self):
        """
        Get the connections from inputs and outputs of this block.
        Returns
        -------
        c : :obj:`List` of :obj:`BlockItem`
        """
        c = []
        for i in self.inputs:
            for cl in i.connectionList:
                c.append(cl)
        for o in self.outputs:
            for cl in o.connectionList:
                c.append(cl)
        return c

    # Scaling related
    def mousePressEvent(self, event):  # create resizer
        """
        Using try catch to avoid creating extra resizers.

        When an item is clicked on, it will check if a resizer already existed. If
        there exist a resizer, returns. else, creates one.

        Resizer will not be created for GenericBlock due to complications in the code.
        Resizer will not be created for storageTank as there's already a built in function for it in the storageTank
        dialog.

        Resizers are deleted inside mousePressEvent function inside GUI.py

        """
        self.logger.debug("Inside Block Item mouse click")

        self.isSelected = True
        if self.name == "GenericBlock" or self.name == "StorageTank":
            return
        try:
            self.resizer
        except AttributeError:
            self.resizer = ResizerItem(self)
            self.resizer.setPos(self.w, self.h)
            self.resizer.itemChange(self.resizer.ItemPositionChange,
                                    self.resizer.pos())
        else:
            return

    def setItemSize(self, w, h):
        self.logger.debug("Inside block item set item size")
        self.w, self.h = w, h
        # if h < 20:
        #     self.h = 20
        # if w < 40:
        #     self.w = 40

    def updateImage(self):
        self.logger.debug("Inside block item update image")

        pixmap = self._getPixmap()
        self.setPixmap(pixmap)

        if self.flippedH:
            self.updateFlipStateH(self.flippedH)

        if self.flippedV:
            self.updateFlipStateV(self.flippedV)

    def _getPixmap(self) -> QPixmap:
        imageAccessor = self._getImageAccessor()

        image = imageAccessor.image(width=self.w, height=self.h).mirrored(
            horizontal=self.flippedH, vertical=self.flippedV)
        pixmap = QPixmap(image)

        return pixmap

    def deleteResizer(self):
        try:
            self.resizer
        except AttributeError:
            self.logger.debug("No resizer")
        else:
            del self.resizer

    # AlignMode related
    def itemChange(self, change, value):
        # self.logger.debug(change, value)
        # Snap grid excludes alignment

        if change == self.ItemPositionChange:
            if self.parent.parent().snapGrid:
                snapSize = self.parent.parent().snapSize
                self.logger.debug("itemchange")
                self.logger.debug(type(value))
                value = QPointF(value.x() - value.x() % snapSize,
                                value.y() - value.y() % snapSize)
                return value
            else:
                # if self.hasElementsInYBand() and not self.elementInY() and not self.aligned:
                if self.parent.parent().alignMode:
                    if self.hasElementsInYBand():
                        return self.alignBlock(value)
                    else:
                        # self.aligned = False
                        return value

                else:
                    return value
        else:
            return super(BlockItem, self).itemChange(change, value)

    def alignBlock(self, value):
        for t in self.parent.parent().trnsysObj:
            if isinstance(t, BlockItem) and t is not self:
                if self.elementInYBand(t):
                    value = QPointF(self.pos().x(), t.pos().y())
                    self.parent.parent().alignYLineItem.setLine(
                        self.pos().x() + self.w / 2,
                        t.pos().y(),
                        t.pos().x() + t.w / 2,
                        t.pos().y())

                    self.parent.parent().alignYLineItem.setVisible(True)

                    qtm = QTimer(self.parent.parent())
                    qtm.timeout.connect(self.timerfunc)
                    qtm.setSingleShot(True)
                    qtm.start(1000)

                    e = QMouseEvent(
                        QEvent.MouseButtonRelease,
                        self.pos(),
                        QtCore.Qt.NoButton,
                        QtCore.Qt.NoButton,
                        QtCore.Qt.NoModifier,
                    )
                    self.parent.mouseReleaseEvent(e)
                    self.parent.parent().alignMode = False
                    # self.setPos(self.pos().x(), t.pos().y())
                    # self.aligned = True

                if self.elementInXBand(t):
                    value = QPointF(t.pos().x(), self.pos().y())
                    self.parent.parent().alignXLineItem.setLine(
                        t.pos().x(),
                        t.pos().y() + self.w / 2,
                        t.pos().x(),
                        self.pos().y() + t.w / 2)

                    self.parent.parent().alignXLineItem.setVisible(True)

                    qtm = QTimer(self.parent.parent())
                    qtm.timeout.connect(self.timerfunc2)
                    qtm.setSingleShot(True)
                    qtm.start(1000)

                    e = QMouseEvent(
                        QEvent.MouseButtonRelease,
                        self.pos(),
                        QtCore.Qt.NoButton,
                        QtCore.Qt.NoButton,
                        QtCore.Qt.NoModifier,
                    )
                    self.parent.mouseReleaseEvent(e)
                    self.parent.parent().alignMode = False

        return value

    def timerfunc(self):
        self.parent.parent().alignYLineItem.setVisible(False)

    def timerfunc2(self):
        self.parent.parent().alignXLineItem.setVisible(False)

    def hasElementsInYBand(self):
        for t in self.parent.parent().trnsysObj:
            if isinstance(t, BlockItem):
                if self.elementInYBand(t):
                    return True

        return False

    def hasElementsInXBand(self):
        for t in self.parent.parent().trnsysObj:
            if isinstance(t, BlockItem):
                if self.elementInXBand(t):
                    return True

        return False

    def elementInYBand(self, t):
        eps = 50
        return self.scenePos().y() - eps <= t.scenePos().y(
        ) <= self.scenePos().y() + eps

    def elementInXBand(self, t):
        eps = 50
        return self.scenePos().x() - eps <= t.scenePos().x(
        ) <= self.scenePos().x() + eps

    def elementInY(self):
        for t in self.parent.parent().trnsysObj:
            if isinstance(t, BlockItem):
                if self.scenePos().y == t.scenePos().y():
                    return True
        return False

    def encode(self):
        portListInputs = []
        portListOutputs = []

        for inp in self.inputs:
            portListInputs.append(inp.id)
        for output in self.outputs:
            portListOutputs.append(output.id)

        blockPosition = (float(self.pos().x()), float(self.pos().y()))

        blockItemModel = BlockItemModel(
            self.name,
            self.displayName,
            blockPosition,
            self.id,
            self.trnsysId,
            portListInputs,
            portListOutputs,
            self.flippedH,
            self.flippedV,
            self.rotationN,
        )

        dictName = "Block-"
        return dictName, blockItemModel.to_dict()

    def decode(self, i, resBlockList):
        model = BlockItemModel.from_dict(i)

        self.setName(model.BlockDisplayName)
        self.setPos(float(model.blockPosition[0]),
                    float(model.blockPosition[1]))
        self.id = model.Id
        self.trnsysId = model.trnsysId

        if len(self.inputs) != len(model.portsIdsIn) or len(
                self.outputs) != len(model.portsIdsOut):
            temp = model.portsIdsIn
            model.portsIdsIn = model.portsIdsOut
            model.portsIdsOut = temp

        for index, inp in enumerate(self.inputs):
            inp.id = model.portsIdsIn[index]

        for index, out in enumerate(self.outputs):
            out.id = model.portsIdsOut[index]

        self.updateFlipStateH(model.flippedH)
        self.updateFlipStateV(model.flippedV)
        self.rotateBlockToN(model.rotationN)

        resBlockList.append(self)

    def decodePaste(self, i, offset_x, offset_y, resConnList, resBlockList,
                    **kwargs):
        self.setPos(
            float(i["BlockPosition"][0] + offset_x),
            float(i["BlockPosition"][1] + offset_y),
        )

        self.updateFlipStateH(i["FlippedH"])
        self.updateFlipStateV(i["FlippedV"])
        self.rotateBlockToN(i["RotationN"])

        for x in range(len(self.inputs)):
            self.inputs[x].id = i["PortsIDIn"][x]

        for x in range(len(self.outputs)):
            self.outputs[x].id = i["PortsIDOut"][x]

        resBlockList.append(self)

    # Export related
    def exportBlackBox(self):
        equation = []
        if (len(self.inputs + self.outputs) == 2 and self.isVisible()
                and not isinstance(self.outputs[0], DoublePipePortItem)):
            files = glob.glob(os.path.join(self.path, "**/*.ddck"),
                              recursive=True)
            if not (files):
                status = "noDdckFile"
            else:
                status = "noDdckEntry"
            lines = []
            for file in files:
                infile = open(file, "r")
                lines += infile.readlines()
            for i in range(len(lines)):
                if "output" in lines[i].lower() and "to" in lines[i].lower(
                ) and "hydraulic" in lines[i].lower():
                    for j in range(i, len(lines) - i):
                        if lines[j][0] == "T":
                            outputT = lines[j].split("=")[0].replace(" ", "")
                            status = "success"
                            break
                    equation = ["T" + self.displayName + "=" + outputT]
                    break
        else:
            status = "noBlackBoxOutput"

        if status == "noDdckFile" or status == "noDdckEntry":
            equation.append("T" + self.displayName + "=1")

        return status, equation

    def exportPumpOutlets(self):
        return "", 0

    def exportMassFlows(self):
        return "", 0

    def exportDivSetting1(self):
        return "", 0

    def exportDivSetting2(self, nUnit):
        return "", nUnit

    def exportPipeAndTeeTypesForTemp(self, startingUnit):
        return "", startingUnit

    def getTemperatureVariableName(self, portItem: SinglePipePortItem) -> str:
        return f"T{self.displayName}"

    def getFlowSolverParametersId(self, portItem: SinglePipePortItem) -> int:
        return self.trnsysId

    def assignIDsToUninitializedValuesAfterJsonFormatMigration(
            self, generator: _id.IdGenerator) -> None:
        pass

    def deleteLoadedFile(self):
        for items in self.loadedFiles:
            try:
                self.parent.parent().fileList.remove(str(items))
            except ValueError:
                self.logger.debug("File already deleted from file list.")
                self.logger.debug("filelist:", self.parent.parent().fileList)
Exemple #25
0
class RuleConditionItem(GraphicsItem):
    def __init__(self, model_item: SimulatorRuleCondition, parent=None):
        assert isinstance(model_item, SimulatorRuleCondition)
        super().__init__(model_item=model_item, parent=parent)

        self.number.setFont(self.font_bold)

        self.text = QGraphicsTextItem(self)
        self.text.setPlainText(self.model_item.type.value)
        self.text.setFont(self.font_bold)

        self.desc = QGraphicsTextItem(self)
        self.desc.setFont(self.font)

    def update_flags(self):
        if self.scene().mode == 0:
            self.set_flags(is_selectable=True, accept_hover_events=True, accept_drops=True)
        else:
            self.set_flags(is_selectable=True, accept_hover_events=True)

    def labels_width(self):
        return max(self.number.boundingRect().width() + self.text.boundingRect().width(),
                   self.desc.boundingRect().width())

    def refresh(self):
        if len(self.model_item.condition):
            if len(self.model_item.condition) > 20:
                self.desc.setPlainText(self.model_item.condition[:20] + "...")
            else:
                self.desc.setPlainText(self.model_item.condition)
        elif self.model_item.type != ConditionType.ELSE:
            self.desc.setPlainText("<Condition>")

    def update_position(self, x_pos, y_pos):
        self.setPos(x_pos, y_pos)

        start_y = 0
        start_x = ((self.scene().items_width() + 40) - (
                    self.number.boundingRect().width() + self.text.boundingRect().width())) / 2
        self.number.setPos(start_x, start_y)
        start_x += self.number.boundingRect().width()
        self.text.setPos(start_x, start_y)
        start_y += round(self.number.boundingRect().height())
        start_x = ((self.scene().items_width() + 40) - self.desc.boundingRect().width()) / 2
        self.desc.setPos(start_x, start_y)

        if self.model_item.type != ConditionType.ELSE:
            start_y += round(self.desc.boundingRect().height())

        start_y += 5

        for child in self.get_scene_children():
            child.update_position(20, start_y)
            start_y += round(child.boundingRect().height())

        width = self.scene().items_width()
        self.prepareGeometryChange()
        self.bounding_rect = QRectF(0, 0, width + 40, self.childrenBoundingRect().height() + 5)

    def update_drop_indicator(self, pos):
        rect = self.boundingRect()

        if pos.y() - rect.top() < rect.height() / 3:
            self.drop_indicator_position = QAbstractItemView.AboveItem
        elif rect.bottom() - pos.y() < rect.height() / 3:
            self.drop_indicator_position = QAbstractItemView.BelowItem
        else:
            self.drop_indicator_position = QAbstractItemView.OnItem

        self.update()

    def paint(self, painter, option, widget):
        if self.scene().mode == 1:
            self.setOpacity(1 if self.model_item.logging_active else 0.3)

        painter.setOpacity(settings.SELECTION_OPACITY)

        if self.hover_active or self.isSelected():
            painter.setBrush(settings.SELECTION_COLOR)
        elif not self.is_valid():
            painter.setBrush(QColor(255, 0, 0, 150))
        else:
            painter.setBrush(QColor.fromRgb(204, 204, 204, 255))

        height = self.number.boundingRect().height()

        if self.model_item.type != ConditionType.ELSE:
            height += self.desc.boundingRect().height()

        painter.drawRect(QRectF(0, 0, self.boundingRect().width(), height))

        painter.setBrush(Qt.NoBrush)
        painter.drawRect(self.boundingRect())

        if self.drag_over:
            self.paint_drop_indicator(painter)

    def paint_drop_indicator(self, painter):
        painter.setPen(QPen(Qt.darkRed, 2, Qt.SolidLine))
        painter.setBrush(Qt.NoBrush)
        rect = self.boundingRect()

        if self.drop_indicator_position == QAbstractItemView.AboveItem:
            painter.drawLine(QLineF(rect.topLeft(), rect.topRight()))
        elif self.drop_indicator_position == QAbstractItemView.OnItem:
            painter.drawRect(rect)
        else:
            painter.drawLine(QLineF(rect.bottomLeft(), rect.bottomRight()))
Exemple #26
0
class QNEPort(QGraphicsPathItem):
    (NamePort, TypePort) = (1, 2)
    (Type) = (QGraphicsItem.UserType + 1)

    def __init__(self, parent):
        super(QNEPort, self).__init__(parent)
        self.textColor = Qt.black

        self.label = QGraphicsTextItem(self)
        self.radius_ = 4
        self.margin = 3

        self.setPen(QPen(Qt.darkRed))
        self.setBrush(Qt.red)

        self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges)

        self.m_portFlags = 0
        self.isOutput_ = False

        self.m_block = None
        self.m_connections = []

    def __del__(self):
        #print("Del QNEPort %s" % self.name)

        for connection in self.m_connections:
            if connection.port1():
                connection.port1().removeConnection(connection)
            if connection.port2():
                connection.port2().removeConnection(connection)
            if self.scene():
                self.scene().removeItem(connection)

    def setName(self, name):
        self.name = name
        self.label.setPlainText(name)
        self.label.setDefaultTextColor(self.textColor)
        self.setBrush(Qt.red)

    def setIsOutput(self, isOutput):
        self.isOutput_ = isOutput

        path = QPainterPath()
        if self.isOutput_:
            if self.name == '':
                path.addRect(-2 * self.radius_, -self.radius_,
                             2 * self.radius_, 2 * self.radius_)
                self.label.setPos(
                    -self.radius_ - self.margin -
                    self.label.boundingRect().width(),
                    -self.label.boundingRect().height() / 2)
            else:
                path.addEllipse(-2 * self.radius_, -self.radius_,
                                2 * self.radius_, 2 * self.radius_)
                self.label.setPos(
                    -self.radius_ - self.margin -
                    self.label.boundingRect().width(),
                    -self.label.boundingRect().height() / 2)
        else:
            if self.name == '':
                path.addRect(0, -self.radius_, 2 * self.radius_,
                             2 * self.radius_)
                self.label.setPos(self.radius_ + self.margin,
                                  -self.label.boundingRect().height() / 2)
            else:
                path.addEllipse(0, -self.radius_, 2 * self.radius_,
                                2 * self.radius_)
                self.label.setPos(self.radius_ + self.margin,
                                  -self.label.boundingRect().height() / 2)

        self.setPath(path)

    def setNEBlock(self, block):
        self.m_block = block

    def setPortFlags(self, flags):
        self.m_portFlags = flags

        if self.m_portFlags & self.TypePort:
            font = self.scene().font()
            font.setItalic(True)
            self.label.setFont(font)
            self.setPath(QPainterPath())
        elif self.m_portFlags & self.NamePort:
            font = self.scene().font()
            font.setBold(True)
            self.label.setFont(font)
            self.setPath(QPainterPath())

    def setPtr(self, ptr):
        self.m_ptr = ptr

    def type(self):
        return self.Type

    def radius(self):
        return self.radius_

    def portName(self):
        return self.name

    def isOutput(self):
        return self.isOutput_

    def block(self):
        return self.m_block

    def portFlags(self):
        return self.m_portFlags

    def ptr(self):
        return self.m_ptr

    def addConnection(self, connection):
        self.m_connections.append(connection)

    def removeConnection(self, connection):
        try:
            self.m_connections.remove(connection)
        except:
            pass

    def connections(self):
        return self.m_connections

    def isConnected(self, other):
        for connection in self.m_connections:
            if connection.port1() == other or connection.port2() == other:
                return True

        return False

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemScenePositionHasChanged:
            for connection in self.m_connections:
                connection.updatePosFromPorts()
                connection.updatePath()

        return value
Exemple #27
0
class Edge(Connection):
    ''' B-spline/Bezier connection shape '''
    def __init__(self, edge, graph):
        ''' Set generic parameters from Connection class '''
        self.text_label = None
        super(Edge, self).__init__(edge['source'], edge['target'])
        self.edge = edge
        self.graph = graph
        # Set connection points as not visible, by default
        self.bezier_visible = False

        # Initialize control point coordinates
        self.bezier = [self.mapFromScene(*self.edge['spline'][0])]
        # Bezier control points (groups of three points):
        assert(len(self.edge['spline']) % 3 == 1)
        for i in xrange(1, len(self.edge['spline']), 3):
            self.bezier.append([Controlpoint(
                          self.mapFromScene(*self.edge['spline'][i + j]), self)
                          for j in range(3)])

        # Create connection points at start and end of the edge
        self.source_connection = Connectionpoint(
                self.start_point or self.bezier[0], self, self.parent)
        self.parent.movable_points.append(self.source_connection)
        self.end_connection = Connectionpoint(
                self.end_point or self.bezier[-1], self, self.child)
        self.child.movable_points.append(self.end_connection)
        self.reshape()

    @property
    def start_point(self):
        ''' Compute connection origin - redefine in subclasses '''
        # Start point is optional - graphviz decision
        return self.mapFromScene(*self.edge['start']) \
               if self.edge.get('start') else None

    @property
    def end_point(self):
        ''' Compute connection end point - redefine in subclasses '''
        return self.mapFromScene(*self.edge['end']) \
               if self.edge.get('end') else None

    def bezier_set_visible(self, visible=True):
        ''' Display or hide the edge control points '''
        self.bezier_visible = visible
        for group in self.bezier[1:]:
            for ctrl_point in group:
                if visible:
                    ctrl_point.show()
                else:
                    ctrl_point.hide()
        if visible:
            self.end_connection.show()
            self.source_connection.show()
        else:
            self.end_connection.hide()
            self.source_connection.hide()
        self.update()

    def mousePressEvent(self, event):
        ''' On a mouse click, display the control points '''
        self.bezier_set_visible(True)

  # pylint: disable=R0914
    def reshape(self):
        ''' Update the shape of the edge (redefined function) '''
        path = QPainterPath()
        # If there is a starting point, draw a line to the first curve point
        if self.start_point:
            path.moveTo(self.source_connection.center)
            path.lineTo(self.bezier[0])
        else:
            path.moveTo(self.source_connection.center)
        # Loop over the curve points:
        for group in self.bezier[1:]:
            path.cubicTo(*[point.center for point in group])

        # If there is an ending point, draw a line to it
        if self.end_point:
            path.lineTo(self.end_connection.center)

        end_point = path.currentPosition()
        arrowhead = self.angle_arrow(path)
        path.lineTo(arrowhead[0])
        path.moveTo(end_point)
        path.lineTo(arrowhead[1])
        path.moveTo(end_point)
        try:
            # Add the transition label, if any (none for the START edge)
            font = QFont('arial', pointSize=8)
            metrics = QFontMetrics(font)
            label = self.edge.get('label', '')
            lines = label.split('\n')
            width = metrics.width(max(lines)) # longest line
            height = metrics.height() * len(lines)
            # lp is the position of the center of the text
            pos = self.mapFromScene(*self.edge['lp'])
            if not self.text_label:
                self.text_label = QGraphicsTextItem(
                                 self.edge.get('label', ''), parent=self)
            self.text_label.setX(pos.x() - width / 2)
            self.text_label.setY(pos.y() - height / 2)
            self.text_label.setFont(font)
            # Make horizontal center alignment, as dot does
            self.text_label.setTextWidth(self.text_label.boundingRect().width())
            fmt = QTextBlockFormat()
            fmt.setAlignment(Qt.AlignHCenter)
            cursor = self.text_label.textCursor()
            cursor.select(QTextCursor.Document)
            cursor.mergeBlockFormat(fmt)
            cursor.clearSelection()
            self.text_label.setTextCursor(cursor)
            self.text_label.show()
        except KeyError:
            # no label
            pass
        self.setPath(path)

    def __str__(self):
        ''' user-friendly information about the edge coordinates '''
        return('Edge between ' + self.edge['source'].name + ' and ' +
                self.edge['target'].name + str(self.edge['spline'][0]))

    def paint(self, painter, option, widget):
        ''' Apply anti-aliasing to Edge Connections '''
        painter.setRenderHint(QPainter.Antialiasing, True)
        super(Edge, self).paint(painter, option, widget)
        # Draw lines between connection points, if visible
        if self.bezier_visible:
            painter.setPen(
                    QPen(Qt.lightGray, 0, Qt.SolidLine))
            painter.setBrush(Qt.NoBrush)
            points_flat = [point.center
                           for sub1 in self.bezier[1:] for point in sub1]
            painter.drawPolyline([self.source_connection.center]
                                  + points_flat + [self.end_connection.center])
Exemple #28
0
class Node(QGraphicsRectItem):
    class io(QGraphicsRectItem):
        class BezierCurve(QGraphicsPathItem):
            def __init__(self, iostart=None, ioend=None):
                super().__init__()

                self.setEnabled(False)  # Make it ignore events. Links can't be interacted with.

                self.iostart = iostart
                self.ioend = ioend

                if iostart is not None and ioend is not None:
                    self.update()
                else:
                    self.update(QPointF(0, 0))

            def update(self, pos=None):
                path = QPainterPath()

                if pos is not None:
                    if self.ioend is None:
                        startpos = self.iostart.pos() + self.iostart.parent.pos()
                        endpos = pos
                    elif self.iostart is None:
                        startpos = pos
                        endpos = self.ioend.pos() + self.ioend.parent.pos()
                else:
                    startpos = self.iostart.pos() + self.iostart.parent.pos()
                    endpos = self.ioend.pos() + self.ioend.parent.pos()

                controlpoint = QPointF(abs((endpos - startpos).x()) * 0.8, 0)

                path.moveTo(startpos)
                path.cubicTo(startpos + controlpoint,
                             endpos - controlpoint,
                             endpos)

                self.setPath(path)

        def __init__(self, parent, index, iotype, iodir):
            self.parent = parent
            self.index = index
            self.iotype = iotype
            self.iodir = iodir
            super().__init__(-8, -8, 16, 16, self.parent)  # Size of io-boxes is 16x16

            self.setAcceptHoverEvents(True)

            self.iobrush = QBrush(QColor(70, 70, 70, 255))
            self.setBrush(self.iobrush)

            self.newbezier = None  # Variable for temporary storage of bezier curve while it's still being dragged
            self.bezier = []

        def mousePressEvent(self, event):
            if event.button() == Qt.LeftButton:
                if self.iodir == "output":
                    self.newbezier = Node.io.BezierCurve(self, None)
                elif self.iodir == "input":
                    self.newbezier = Node.io.BezierCurve(None, self)

                if self.newbezier is not None:
                    self.newbezier.update(QPointF(event.pos() + self.pos() + self.parent.pos()))

                self.parent.parent.scene.addItem(self.newbezier)
            elif event.button() == Qt.RightButton:
                self.delAllBezier()

        def mouseMoveEvent(self, event):
            if self.newbezier is not None:
                self.newbezier.update(QPointF(event.pos() + self.pos() + self.parent.pos()))

        def mouseReleaseEvent(self, event):
            if self.newbezier is not None:
                self.parent.parent.scene.removeItem(self.newbezier)
            self.newbezier = None

            # Find out if an io box lies under the cursor
            pos = event.pos() + self.pos() + self.parent.pos()
            pos = self.parent.parent.mapFromScene(pos)
            target = self.parent.parent.itemAt(pos.x(), pos.y())

            # If io box is found, spawn a bezier curve
            if target is None:
                if self.iodir == "output":
                    ns = NodeSelector(self.parent.parent.modman, modfilter={"type": {"type": self.iotype, "dir": "input"}})
                elif self.iodir == "input":
                    ns = NodeSelector(self.parent.parent.modman, modfilter={"type": {"type": self.iotype, "dir": "output"}})
                if ns.exec():
                    if issubclass(ns.data["node"], baseModule.BaseNode):
                        newNode = Node(self.parent.parent, ns.data["node"])
                        newNode.setPos(event.pos() + self.pos() + self.parent.pos())
                        self.parent.parent.scene.addItem(newNode)
                        if self.iodir == "output":
                            target = newNode.inputIO[ns.data["pin"]]
                        elif self.iodir == "input":
                            target = newNode.outputIO[ns.data["pin"]]

            if target is not None and isinstance(target, Node.io):
                bezier = None
                if self.iodir == "output" and target.iodir == "input" and (self.iotype == target.iotype or not self.iotype or not target.iotype):
                    bezier = Node.io.BezierCurve(self, target)
                    if not self.iotype == "exec":
                        target.delAllBezier()
                    elif self.iotype == "exec":
                        if len(self.bezier) >= 1:
                            self.delAllBezier()
                elif self.iodir == "input" and target.iodir == "output" and (self.iotype == target.iotype or not self.iotype or not target.iotype):
                    bezier = Node.io.BezierCurve(target, self)
                    if not self.iotype == "exec":
                        self.delAllBezier()
                    elif self.iotype == "exec":
                        if len(target.bezier) >= 1:
                            target.delAllBezier()

                if bezier is not None:
                    self.bezier.append(bezier)
                    target.bezier.append(bezier)

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

        def hoverEnterEvent(self, event):
            self.parent.setPen(QPen(QColor("black")))   # For some f*****g reason QGraphicsSceneHoverEvents can't be accepted, so this dirty workaround has to be used...
            self.setPen(QPen(QColor("yellow")))

        def hoverLeaveEvent(self, event):
            self.parent.setPen(QPen(QColor("yellow")))  # See above
            self.setPen(QPen(QColor("black")))

        def updateBezier(self):
            for bezier in self.bezier:
                bezier.update()

        def delAllBezier(self):
            beziercpy = self.bezier[:]
            for bezier in beziercpy:
                bezier.iostart.bezier.remove(bezier)
                bezier.ioend.bezier.remove(bezier)
                self.parent.parent.scene.removeItem(bezier)

    def __init__(self, parent, nodedata=None, id=None):
        if nodedata is None:
            raise ValueError("Nodetype must not be 'None'")

        self.nodedata = nodedata

        self.parent = parent
        self.width = 32
        self.height = 0
        super().__init__(-self.width / 2, -self.height / 2, self.width, self.height)

        self.setAcceptHoverEvents(True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)

        self.extraNodeData = {}

        if id is not None:
            self.id = id
        else:
            self.id = uuid.uuid4().hex    # Random ID to identify node

        self.nodebrush = QBrush(QColor(100, 100, 100, 255))
        self.setBrush(self.nodebrush)

        # Node Title
        self.nodetitle = self.nodedata.name
        self.nodetitleTextItem = QGraphicsTextItem(self.nodetitle, self)
        self.width = max(self.width, self.nodetitleTextItem.boundingRect().width())
        self.height += self.nodetitleTextItem.boundingRect().height()

        # Create all the text items for the IO
        self.inputTextItems = []
        self.outputTextItems = []
        for i in range(max(len(self.nodedata.inputDefs), len(self.nodedata.outputDefs))):
            linewidth = 0
            lineheight = 0
            try:
                self.inputTextItems.append(QGraphicsTextItem(self.nodedata.inputDefs[i][0], self))
                linewidth += self.inputTextItems[i].boundingRect().width()
                lineheight = max(lineheight, self.inputTextItems[i].boundingRect().height())
            except IndexError:
                pass

            try:
                self.outputTextItems.append(QGraphicsTextItem(self.nodedata.outputDefs[i][0], self))
                linewidth += self.outputTextItems[i].boundingRect().width()
                lineheight = max(lineheight, self.outputTextItems[i].boundingRect().height())
            except IndexError:
                pass

            linewidth += 12  # Keep atleast 12px distance between the input and output text
            self.width = max(self.width, linewidth)
            self.height += lineheight

        # Set correct positions for all text items
        self.nodetitleTextItem.setPos(-self.width / 2, -self.height / 2)

        self.inputIO = []
        heightPointer = 0
        for i in range(max(len(self.nodedata.inputDefs), len(self.nodedata.outputDefs))):
            try:
                self.inputTextItems[i].setPos(-self.width / 2,
                                              -self.height / 2 + self.nodetitleTextItem.boundingRect().height() + heightPointer)
                heightPointer += self.inputTextItems[i].boundingRect().height()

                newinput = Node.io(self, i, self.nodedata.inputDefs[i][1], "input")
                self.inputIO.append(newinput)
                newinput.setPos(-self.width / 2 - newinput.rect().width() / 2,
                                -self.height / 2 + heightPointer + self.inputTextItems[i].boundingRect().height() / 2)

            except IndexError:
                pass

        self.outputIO = []
        heightPointer = 0
        for i in range(max(len(self.nodedata.inputDefs), len(self.nodedata.outputDefs))):
            try:
                self.outputTextItems[i].setPos(self.width / 2 - self.outputTextItems[i].boundingRect().width(),
                                               -self.height / 2 + self.nodetitleTextItem.boundingRect().height() + heightPointer)
                heightPointer += self.outputTextItems[i].boundingRect().height()

                newoutput = Node.io(self, i, self.nodedata.outputDefs[i][1], "output")
                self.outputIO.append(newoutput)
                newoutput.setPos(self.width / 2 + newoutput.rect().width() / 2,
                                 -self.height / 2 + heightPointer + self.outputTextItems[i].boundingRect().height() / 2)

            except IndexError:
                pass

        # Set rect to correct size
        self.setRect(-self.width / 2, -self.height / 2, self.width, self.height)

        # Additional stuff
        self.setFlag(QGraphicsItem.ItemIsMovable, True)

    def delete(self):
        for io in self.inputIO + self.outputIO:
            io.delAllBezier()
            io.parent = None
            io.bezier = None

        del self.inputIO
        del self.outputIO

    def mouseMoveEvent(self, event):
        super().mouseMoveEvent(event)

        for io in self.inputIO + self.outputIO:
            io.updateBezier()

    def hoverEnterEvent(self, event):
        self.setPen(QPen(QColor("yellow")))

    def hoverLeaveEvent(self, event):
        self.setPen(QPen(QColor("black")))
class NodeTemplateItem():
    ''' 
    This represents one node template on the diagram.  A node template can be on many diagrams
    This class creates the rectangle graphics item and the text graphics item and adds them to the scene.
    '''
    def __init__(self, scene, x, y, nodeTemplateDict=None, NZID=None):
        self.scene = scene
        self.logMsg = None
        self.x = x
        self.y = y
        self.nodeTemplateDict = nodeTemplateDict
        #        self.name = self.nodeTemplateDict.get("name", "")   THIS HAS BEEN REPLACED BY THE name FUNCTION - SEE BELOW
        self.diagramType = "Node Template"
        self.displayText = None
        self.model = self.scene.parent.model
        self.gap = 100
        self.relList = []
        # assign a unique key if it doesn't already have one
        if NZID == None:
            self.NZID = str(uuid.uuid4())
        else:
            self.NZID = NZID

        # init graphics objects to none
        self.TNode = None
        self.TNtext = None

        # draw the node template on the diagram
        self.drawIt()

    def name(self, ):
        return self.nodeTemplateDict.get("name", "")

    def getX(self, ):
        return self.TNode.boundingRect().x()

    def getY(self, ):
        return self.TNode.boundingRect().y()

    def getHeight(self, ):
        return self.TNode.boundingRect().height()

    def getWidth(self, ):
        return self.TNode.boundingRect().width()

    def getRelList(self, ):
        '''return a list of all relationitems that are inbound or outbound from this node template.
          do not include self referencing relationships
        '''
        return [
            diagramItem
            for key, diagramItem in self.scene.parent.itemDict.items()
            if diagramItem.diagramType == "Relationship Template" and (
                diagramItem.startNZID == self.NZID
                or diagramItem.endNZID == self.NZID)
        ]

    def getPoint(self, offset=None):
        '''
        This function is used by the template diagram to calculate the location to drop a node template on the diagram
        '''
        if offset is None:
            return QPointF(self.x, self.y)
        else:
            return QPointF(self.x + offset, self.y + offset)

    def getFormat(self, ):
        '''
        determine if the Node Template  has a template format or should use the project default format
        '''
        # get the node Template custom format
        customFormat = self.nodeTemplateDict.get("TNformat", None)

        if not customFormat is None:
            # get the template custom format
            self.nodeFormat = TNodeFormat(formatDict=customFormat)
        else:
            # get the project default format
            self.nodeFormat = TNodeFormat(
                formatDict=self.model.modelData["TNformat"])

    def clearItem(self, ):

        if (not self.TNode is None and not self.TNode.scene() is None):
            self.TNode.scene().removeItem(self.TNode)
        if (not self.TNtext is None and not self.TNtext.scene() is None):
            self.TNtext.scene().removeItem(self.TNtext)

    def drawIt(self, ):

        # get current format as it may have changed
        self.getFormat()

        # create the qgraphicsItems if they don't exist
        if self.TNode is None:
            # create the rectangle
            self.TNode = QGraphicsRectItem(QRectF(
                self.x, self.y, self.nodeFormat.formatDict["nodeWidth"],
                self.nodeFormat.formatDict["nodeHeight"]),
                                           parent=None)
            self.TNode.setZValue(NODELAYER)
            self.TNode.setFlag(QGraphicsItem.ItemIsMovable, True)
            self.TNode.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
            self.TNode.setFlag(QGraphicsItem.ItemIsSelectable, True)
            self.TNode.setSelected(True)
            self.TNode.setData(1, self.NZID)  # get with self.INode.data(1)
            self.TNode.setData(ITEMTYPE, NODETEMPLATE)
            # create the text box
            self.TNtext = QGraphicsTextItem("", parent=None)
            self.TNtext.setPos(self.x, self.y)
            self.TNtext.setFlag(QGraphicsItem.ItemIsMovable, True)
            self.TNtext.setFlag(QGraphicsItem.ItemIsSelectable, False)
            self.TNtext.setData(NODEID, self.NZID)
            self.TNtext.setData(ITEMTYPE, NODETEMPLATETEXT)
            self.TNtext.setZValue(NODELAYER)
            # save the location
            self.x = self.TNode.sceneBoundingRect().x()
            self.y = self.TNode.sceneBoundingRect().y()
            # generate the html and resize the rectangle
            self.formatItem()
            # add the graphics items to the scene
            self.scene.addItem(self.TNode)
            self.scene.addItem(self.TNtext)
        else:
            # generate the html and resize the rectangle
            self.formatItem()

    def formatItem(self, ):

        # configure the formatting aspects of the qgraphics item
        pen = self.nodeFormat.pen()
        brush = self.nodeFormat.brush()
        self.TNode.setBrush(brush)
        self.TNode.setPen(pen)

        # generate the HTML
        genHTML = self.generateHTML()
        self.TNtext.prepareGeometryChange()
        #        print("before html bounding rectangle width:{}".format(self.TNtext.boundingRect().width()))
        #        print("before html text width:{}".format(self.TNtext.textWidth()))
        self.TNtext.setTextWidth(
            -1
        )  # reset the width to unkonwn so it will calculate a new width based on the new html
        self.TNtext.setHtml(genHTML)
        #        print("after html bounding rectangle width:{}".format(self.TNtext.boundingRect().width()))
        #        print("after html text width:{}".format(self.TNtext.textWidth()))

        # make sure minimum width of 120
        if self.TNtext.boundingRect().width() < 120:
            self.TNtext.setTextWidth(120)
        else:
            self.TNtext.setTextWidth(
                self.TNtext.boundingRect().width()
            )  # you have to do a setTextWidth to get the html to render correctly.

        # set the rectangle item to the same size as the formatted html
        self.TNode.prepareGeometryChange()
        currentRect = self.TNode.rect()
        # insure minimum height of 120
        if self.TNtext.boundingRect().height() < 120:
            currentRect.setHeight(120)
        else:
            currentRect.setHeight(self.TNtext.boundingRect().height())
        currentRect.setWidth(self.TNtext.boundingRect().width())
        self.TNode.setRect(currentRect)

    def generateHTML(self, ):
        '''
        Generate the HTML that formats the node template data inside the rectangle
        '''
        # generate the html
        prefix = "<!DOCTYPE html><html><body>"
        #        head = "<head><style>table, th, td {border: 1px solid black; border-collapse: collapse;}</style></head>"
        suffix = "</body></html>"
        #        blankRow = "<tr><td><left>{}</left></td><td><left>{}</left></td><td><left>{}</left></td><td><left>{}</left></td></tr>".format("", "", "", "")

        name = "<center><b>{}</b></center>".format(
            self.nodeTemplateDict.get("name", ""))
        lbls = self.genLblHTML()
        props = self.genPropHTML()
        genHTML = "{}{}<hr>{}<br><hr>{}{}".format(prefix, name, lbls, props,
                                                  suffix)
        #        print("{} html: {}".format(self.name(), genHTML))

        return genHTML

    def genLblHTML(self):
        #        html = '<table width="90%">'
        html = '<table style="width:90%;border:1px solid black;">'
        if len(self.nodeTemplateDict.get("labels", [])) > 0:
            for lbl in self.nodeTemplateDict.get("labels", []):
                if lbl[NODEKEY] == Qt.Checked:
                    nk = "NK"
                else:
                    nk = "&nbsp;&nbsp;"
                if lbl[REQUIRED] == Qt.Checked:
                    rq = "R"
                else:
                    rq = ""

                html = html + '<tr align="left"><td width="15%"><left>{}</left></td><td width="65%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td></tr>'.format(
                    nk, lbl[LABEL], "", rq)
            html = html + "</table>"
        else:
            html = '<tr align="left"><td width="15%"><left>{}</left></td><td  width="65%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td></tr>'.format(
                "  ", "NO{}LABELS".format("&nbsp;"), "", "")
            html = html + "</table>"

        return html

    def genPropHTML(self):
        #        PROPERTY, DATATYPE, PROPREQ, DEFAULT, EXISTS, UNIQUE, PROPNODEKEY
        html = '<table style="width:90%;border:1px solid black;">'
        if len(self.nodeTemplateDict.get("properties", [])) > 0:
            for prop in self.nodeTemplateDict.get("properties", []):
                if prop[PROPNODEKEY] == Qt.Checked:
                    nk = "NK"
                else:
                    nk = "&nbsp;&nbsp;"
                if prop[PROPREQ] == Qt.Checked:
                    rq = "R"
                else:
                    rq = ""
                if prop[EXISTS] == Qt.Checked:
                    ex = "E"
                else:
                    ex = ""
                if prop[UNIQUE] == Qt.Checked:
                    uq = "U"
                else:
                    uq = ""
                html = html + '<tr align="left"><td width="15%"><left>{}</left></td><td width="65%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td></tr>'.format(
                    nk, prop[PROPERTY], rq, ex, uq)
            html = html + "</table>"
        else:
            html = html + '<tr align="left"><td width="15%"><left>{}</left></td><td width="65%"><left>{}</left></td><td width="10%"><left>{}</left></td><td width="10%"><left>{}</left></td></tr>'.format(
                "&nbsp;&nbsp;", "NO{}PROPERTIES".format("&nbsp;"), "", "", "")
            html = html + "</table>"
        return html

    def moveIt(self, dx, dy):
        '''
        Move the node rectangle and the node textbox to the delta x,y coordinate.
        '''
        #        print("before moveIt: sceneboundingrect {} ".format( self.INode.sceneBoundingRect()))

        self.TNode.moveBy(dx, dy)
        self.x = self.TNode.sceneBoundingRect().x()
        self.y = self.TNode.sceneBoundingRect().y()
        self.TNtext.moveBy(dx, dy)
        #        print("after moveIt: sceneboundingrect {} ".format( self.INode.sceneBoundingRect()))
        # now redraw all the relationships
        self.drawRels()

    def drawRels(self, ):
        '''Redraw all the relationship lines connected to the Node Template Rectangle'''
        # get a list of the relationship items connected to this node template
        self.relList = self.getRelList()

        # assign the correct inbound/outbound side for the rel
        for rel in self.relList:
            if rel.endNodeItem.NZID != rel.startNodeItem.NZID:  # ignore bunny ears
                rel.assignSide()
        # get a set of all the nodes and sides involved
        nodeSet = set()
        for rel in self.relList:
            if rel.endNodeItem.NZID != rel.startNodeItem.NZID:  # ignore bunny ears
                nodeSet.add((rel.endNodeItem, rel.inboundSide))
                nodeSet.add((rel.startNodeItem, rel.outboundSide))

        # tell each node side to assign rel locations
        for nodeSide in nodeSet:
            nodeSide[0].assignPoint(nodeSide[1])

        ############################################

        # now tell them all to redraw
        for rel in self.relList:
            rel.drawIt2()

    def calcOffset(self, index, totRels):
        offset = [-60, -40, -20, 0, 20, 40, 60]
        offsetStart = [3, 2, 2, 1, 1, 0, 0]
        if totRels > 7:
            totRels = 7
        return offset[offsetStart[totRels - 1] + index]

    def assignPoint(self, side):
        # go through all the rels on a side and assign their x,y coord for that side
        self.relList = self.getRelList()
        sideList = [
            rel for rel in self.relList
            if ((rel.startNZID == self.NZID and rel.outboundSide == side) or (
                rel.endNZID == self.NZID and rel.inboundSide == side))
        ]
        totRels = len(sideList)
        if totRels > 0:
            if side == R:
                # calc center of the side
                x = self.x + self.getWidth()
                y = self.y + self.getHeight() / 2
                # sort the rels connected to this side by the y value
                sideList.sort(key=self.getSortY)
                # assign each of them a position on the side starting in the center and working out in both directions
                for index, rel in enumerate(sideList):
                    if rel.startNZID == self.NZID:
                        rel.outboundPoint = QPointF(
                            x, y + (self.calcOffset(index, totRels)))
                    if rel.endNZID == self.NZID:
                        rel.inboundPoint = QPointF(
                            x, y + (self.calcOffset(index, totRels)))
            elif side == L:
                x = self.x
                y = self.y + self.getHeight() / 2
                sideList.sort(key=self.getSortY)
                for index, rel in enumerate(sideList):
                    if rel.startNZID == self.NZID:
                        rel.outboundPoint = QPointF(
                            x, y + (self.calcOffset(index, totRels)))
                    if rel.endNZID == self.NZID:
                        rel.inboundPoint = QPointF(
                            x, y + (self.calcOffset(index, totRels)))
            elif side == TOP:
                x = self.x + self.getWidth() / 2
                y = self.y
                sideList.sort(key=self.getSortX)
                for index, rel in enumerate(sideList):
                    if rel.startNZID == self.NZID:
                        rel.outboundPoint = QPointF(
                            x + (self.calcOffset(index, totRels)), y)
                    if rel.endNZID == self.NZID:
                        rel.inboundPoint = QPointF(
                            x + (self.calcOffset(index, totRels)), y)
            elif side == BOTTOM:
                x = self.x + self.getWidth() / 2
                y = self.y + self.getHeight()
                sideList.sort(key=self.getSortX)
                for index, rel in enumerate(sideList):
                    if rel.startNZID == self.NZID:
                        rel.outboundPoint = QPointF(
                            x + (self.calcOffset(index, totRels)), y)
                    if rel.endNZID == self.NZID:
                        rel.inboundPoint = QPointF(
                            x + (self.calcOffset(index, totRels)), y)
            else:
                print("error, no side")

    def getSortY(self, rel):
        # if this node is the start node then return the end node's Y
        if rel.startNZID == self.NZID:
            return rel.endNodeItem.TNode.sceneBoundingRect().center().y()
        # if this node is the end node then return the start node's Y
        if rel.endNZID == self.NZID:
            return rel.startNodeItem.TNode.sceneBoundingRect().center().y()
        # this should never happen
        return 0

    def getSortX(self, rel):
        # if this node is the start node then return the end node's X
        if rel.startNZID == self.NZID:
            return rel.endNodeItem.TNode.sceneBoundingRect().center().x()
        # if this node is the end node then return the start node's X
        if rel.endNZID == self.NZID:
            return rel.startNodeItem.TNode.sceneBoundingRect().center().x()
        # this should never happen
        return 0

    def getObjectDict(self, ):
        '''
        This function returns a dictionary with all the data that represents this node template item.  
        The dictionary is added to the Instance Diagram dictionary.'''
        objectDict = {}
        objectDict["NZID"] = self.NZID
        objectDict["name"] = self.nodeTemplateDict.get("name", "")
        objectDict["displayText"] = self.displayText
        objectDict["x"] = self.TNode.sceneBoundingRect().x()
        objectDict["y"] = self.TNode.sceneBoundingRect().y()
        objectDict["diagramType"] = self.diagramType
        objectDict["labels"] = self.nodeTemplateDict.get("labels", [])
        objectDict["properties"] = self.nodeTemplateDict.get("properties", [])

        return objectDict

    def setLogMethod(self, logMethod=None):
        if logMethod is None:
            if self.logMsg is None:
                self.logMsg = self.noLog
        else:
            self.logMsg = logMethod

    def noLog(self, msg):
        return
Exemple #30
0
class MessageItem(GraphicsItem):
    def __init__(self, model_item: SimulatorMessage, parent=None):
        assert isinstance(model_item, SimulatorMessage)
        super().__init__(model_item=model_item, parent=parent)

        self.setFlag(QGraphicsItem.ItemIsPanel, True)
        self.arrow = MessageArrowItem(self)

        self.repeat_text = QGraphicsTextItem(self)
        self.repeat_text.setFont(self.font)

    def update_flags(self):
        if self.scene().mode == 0:
            self.set_flags(is_selectable=True, is_movable=True, accept_hover_events=True, accept_drops=True)

    def width(self):
        labels = self.labels()
        width = self.number.boundingRect().width()
        # width += 5
        width += sum([lbl.boundingRect().width() for lbl in labels])
        width += 5 * (len(labels) - 1)
        width += self.repeat_text.boundingRect().width()

        return width

    def refresh(self):
        self.repeat_text.setPlainText("(" + str(self.model_item.repeat) + "x)" if self.model_item.repeat > 1 else "")

    def labels(self):
        self.refresh_unlabeled_range_marker()
        unlabeled_range_items = [uri for uri in self.childItems() if isinstance(uri, UnlabeledRangeItem)]
        result = []

        start = 0
        i = 0

        message = self.model_item

        if len(message) and not message.message_type:
            result.append(unlabeled_range_items[0])
        else:
            for lbl in message.message_type:
                if lbl.start > start:
                    result.append(unlabeled_range_items[i])
                    i += 1

                result.append(self.scene().model_to_scene(lbl))
                start = lbl.end

            if start < len(message):
                result.append(unlabeled_range_items[i])

        return result

    def refresh_unlabeled_range_marker(self):
        msg = self.model_item

        urm = [item for item in self.childItems() if isinstance(item, UnlabeledRangeItem)]

        if len(msg):
            num_unlabeled_ranges = len(msg.message_type.unlabeled_ranges)

            if msg.message_type and msg.message_type[-1].end >= len(msg):
                num_unlabeled_ranges -= 1
        else:
            num_unlabeled_ranges = 0

        if len(urm) < num_unlabeled_ranges:
            for i in range(num_unlabeled_ranges - len(urm)):
                UnlabeledRangeItem(self)
        else:
            for i in range(len(urm) - num_unlabeled_ranges):
                self.scene().removeItem(urm[i])

    def update_position(self, x_pos, y_pos):
        labels = self.labels()
        self.setPos(QPointF(x_pos, y_pos))

        p_source = self.mapFromItem(self.source.line, self.source.line.line().p1())
        p_destination = self.mapFromItem(self.destination.line, self.destination.line.line().p1())

        arrow_width = abs(p_source.x() - p_destination.x())

        start_x = min(p_source.x(), p_destination.x())
        start_x += (arrow_width - self.width()) / 2
        start_y = 0

        self.number.setPos(start_x, start_y)
        start_x += self.number.boundingRect().width()

        for label in labels:
            label.setPos(start_x, start_y)
            start_x += label.boundingRect().width() + 5

        self.repeat_text.setPos(start_x, start_y)

        if labels:
            start_y += labels[0].boundingRect().height() + 5
        else:
            start_y += 26

        self.arrow.setLine(p_source.x(), start_y, p_destination.x(), start_y)
        super().update_position(x_pos, y_pos)

    @property
    def source(self):
        return self.scene().participants_dict[self.model_item.participant]

    @property
    def destination(self):
        return self.scene().participants_dict[self.model_item.destination]
Exemple #31
0
class MatchEnd(InfoScene):
    def __init__(self, parent):
        super().__init__()
        self.__parent__ = parent

        self.font = QFont()
        self.font.setPointSize(20)
        self.my_points = QGraphicsTextItem(str(self.__parent__.my_score))
        self.my_points.setDefaultTextColor(Qt.white)
        self.my_points.setFont(self.font)
        self.opponent_points = QGraphicsTextItem(
            str(self.__parent__.opponent_score))
        self.opponent_points.setDefaultTextColor(Qt.white)
        self.opponent_points.setFont(self.font)
        self.logo = QGraphicsPixmapItem()

        self.logo.setPos((SCENE_WIDTH - 600) / 2, 50)

        if self.__parent__.player == Player.PLAYER_1:
            self.my_points.setPos(50, 250)
            self.opponent_points.setPos(
                SCENE_WIDTH -
                (50 + self.opponent_points.boundingRect().width()), 250)
        else:
            self.opponent_points.setPos(50, 250)
            self.my_points.setPos(
                SCENE_WIDTH -
                (50 + self.opponent_points.boundingRect().width()), 250)

        self.buttons = [
            Button(self.__parent__.load_info_scene, InfoScenes.MAIN_MENU.value,
                   (SCENE_WIDTH - 300) / 2, SCENE_HEIGHT - 100,
                   IMAGES_DIR + "menu/continue_highlighted.png",
                   IMAGES_DIR + "menu/continue_highlighted.png",
                   ButtonState.HIGHLIGHTED)
        ]

        if self.__parent__.my_score == self.__parent__.opponent_score:
            self.logo.setPixmap(QPixmap(IMAGES_DIR + "menu/draw.png"))
        elif self.__parent__.my_score > self.__parent__.opponent_score:
            self.logo.setPixmap(QPixmap(IMAGES_DIR + "menu/you_won.png"))
        else:
            self.logo.setPixmap(QPixmap(IMAGES_DIR + "menu/you_lost.png"))

        self.__draw_menu_buttons()
        self.addItem(self.my_points)
        self.addItem(self.opponent_points)
        self.addItem(self.logo)

    """ Handles keyboard presses """

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_W:
            self.__change_button_focus(Direction.UP)
        elif event.key() == Qt.Key_S:
            self.__change_button_focus(Direction.DOWN)
        elif event.key() == Qt.Key_Return:
            self.__execute_button()

    """ Draws buttons in the scene """

    def __draw_menu_buttons(self):
        for button in self.buttons:
            self.addItem(button.graphics_item)

    """ Executes button logic """

    def __execute_button(self):
        for index in range(len(self.buttons)):
            self.buttons[index].execute()

    """ Changes button focus """

    def __change_button_focus(self, direction: Direction):
        if direction is None:
            return

        count = len(self.buttons)
        old_index = -1
        new_index = -1
        for index in range(count):
            if self.buttons[index].state is ButtonState.HIGHLIGHTED:
                old_index = index
                if direction is Direction.UP:
                    if index - 1 > 0:
                        new_index = index - 1
                    else:
                        new_index = 0
                elif direction is Direction.DOWN:
                    if index + 1 > count - 1:
                        new_index = count - 1
                    else:
                        new_index = index + 1

        self.buttons[old_index].set_state(ButtonState.NORMAL)
        self.buttons[new_index].set_state(ButtonState.HIGHLIGHTED)
Exemple #32
0
    textItem = QGraphicsTextItem()
    textItem.setHtml(
        "<font color=\"white\"><b>Stickman</b>"
        "<p>"
        "Tell the stickman what to do!"
        "</p>"
        "<p><i>"
        "<li>Press <font color=\"purple\">J</font> to make the stickman jump.</li>"
        "<li>Press <font color=\"purple\">D</font> to make the stickman dance.</li>"
        "<li>Press <font color=\"purple\">C</font> to make him chill out.</li>"
        "<li>When you are done, press <font color=\"purple\">Escape</font>.</li>"
        "</i></p>"
        "<p>If he is unlucky, the stickman will get struck by lightning, and never jump, dance or chill out again."
        "</p></font>")

    w = textItem.boundingRect().width()
    stickManBoundingRect = stickMan.mapToScene(
        stickMan.boundingRect()).boundingRect()
    textItem.setPos(-w / 2.0, stickManBoundingRect.bottom() + 25.0)

    scene = QGraphicsScene()
    scene.addItem(stickMan)
    scene.addItem(textItem)
    scene.setBackgroundBrush(Qt.black)

    view = GraphicsView()
    view.setRenderHints(QPainter.Antialiasing)
    view.setTransformationAnchor(QGraphicsView.NoAnchor)
    view.setScene(scene)
    view.show()
    view.setFocus()
Exemple #33
0
    def createGraphics(self):
        """ Create the graphical representation of the FMU's inputs and outputs """
        def variableColor(variable):
            if variable.type == 'Real':
                return QColor.fromRgb(0, 0, 127)
            elif variable.type in ['Integer', 'Enumeration']:
                return QColor.fromRgb(255, 127, 0)
            elif variable.type == 'Boolean':
                return QColor.fromRgb(255, 0, 255)
            elif variable.type == 'String':
                return QColor.fromRgb(0, 128, 0)
            else:
                return QColor.fromRgb(0, 0, 0)

        inputVariables = []
        outputVariables = []
        maxInputLabelWidth = 0
        maxOutputLabelWidth = 0

        textItem = QGraphicsTextItem()
        fontMetrics = QFontMetricsF(textItem.font())

        for variable in self.modelDescription.modelVariables:
            if variable.causality == 'input':
                inputVariables.append(variable)
            elif variable.causality == 'output':
                outputVariables.append(variable)

        for variable in inputVariables:
            maxInputLabelWidth = max(maxInputLabelWidth,
                                     fontMetrics.width(variable.name))

        for variable in outputVariables:
            maxOutputLabelWidth = max(maxOutputLabelWidth,
                                      fontMetrics.width(variable.name))

        from math import floor

        scene = QGraphicsScene()
        self.ui.graphicsView.setScene(scene)
        group = QGraphicsItemGroup()
        scene.addItem(group)
        group.setPos(200.5, -50.5)
        lh = 15  # line height

        w = max(150., maxInputLabelWidth + maxOutputLabelWidth + 20)
        h = max(50., 10 + lh * max(len(inputVariables), len(outputVariables)))

        block = QGraphicsRectItem(0, 0, w, h, group)
        block.setPen(QColor.fromRgb(0, 0, 255))

        pen = QPen()
        pen.setWidthF(1)

        font = QFont()
        font.setPixelSize(10)

        # inputs
        y = floor((h - len(inputVariables) * lh) / 2 - 2)
        for variable in inputVariables:
            text = QGraphicsTextItem(variable.name, group)
            text.setDefaultTextColor(QColor.fromRgb(0, 0, 255))
            text.setFont(font)
            text.setX(3)
            text.setY(y)

            polygon = QPolygonF([
                QPointF(-13.5, y + 4),
                QPointF(1, y + 11),
                QPointF(-13.5, y + 18)
            ])

            path = QPainterPath()
            path.addPolygon(polygon)
            path.closeSubpath()
            contour = QGraphicsPathItem(path, group)
            contour.setPen(QPen(Qt.NoPen))
            contour.setBrush(variableColor(variable))

            y += lh

        # outputs
        y = floor((h - len(outputVariables) * lh) / 2 - 2)
        for variable in outputVariables:
            text = QGraphicsTextItem(variable.name, group)
            text.setDefaultTextColor(QColor.fromRgb(0, 0, 255))
            text.setFont(font)
            text.setX(w - 3 - text.boundingRect().width())
            text.setY(y)

            polygon = QPolygonF([
                QPointF(w, y + 0 + 7.5),
                QPointF(w + 7, y + 3.5 + 7.5),
                QPointF(w, y + 7 + 7.5)
            ])

            path = QPainterPath()
            path.addPolygon(polygon)
            path.closeSubpath()
            contour = QGraphicsPathItem(path, group)
            pen = QPen()
            pen.setColor(variableColor(variable))
            pen.setJoinStyle(Qt.MiterJoin)
            contour.setPen(pen)

            y += lh
Exemple #34
0
class DetectorBox(QGraphicsRectItem):
    """
    Represents a single detector box in the MultiDetectorSelector widget.
    """
    length = 32
    disabled_brush = QBrush(QColor(210, 210, 210, 200))
    enabled_brush = QBrush(QColor(120, 123, 135, 255))
    hovered_brush = QBrush(QColor(156, 186, 252, 255))
    selected_brush = QBrush(QColor(80, 110, 206, 255))
    invisible_pen = QPen(QColor(255, 255, 255, 0))
    red_pen = QPen(QColor('red'))

    def __init__(self, row, column, enabled, *args):

        self._detector_id = box_id(row, column)

        self._enabled = enabled

        self._selected = False
        self._rect = QRectF(*args)
        self._rect.setHeight(self.length)
        self._rect.setWidth(self.length)

        super().__init__(self._rect)

        self.setPen(self.invisible_pen)

        self.setAcceptHoverEvents(True)

        if enabled:
            self.setBrush(self.enabled_brush)
        else:
            self.setBrush(self.disabled_brush)

        # states: enabled, disabled, hovered, selected
        self._label = QGraphicsTextItem(str(self.detector_id), self)

        self._label.setTransform(flip_vertical, True)

        self._label.setFont(QFont('Arial', 14))

        self._label.setDefaultTextColor(QColor('white'))

        self._detector_selector = None

    @property
    def detector_id(self):
        return self._detector_id

    @property
    def size(self):
        return self._rect.size()

    @property
    def selected(self):
        return self._selected

    def set_parent_selector(self, parent):
        self._detector_selector = parent

    def hoverEnterEvent(self, event):
        if self._enabled:
            self.setBrush(self.hovered_brush)

    def hoverLeaveEvent(self, event):
        if self._enabled:
            if self._selected:
                self.setBrush(self.selected_brush)
            else:
                self.setBrush(self.enabled_brush)
        else:
            self.setBrush(self.disabled_brush)

    def mousePressEvent(self, event):
        if self._enabled:
            if event.button() == Qt.LeftButton:
                if not self._selected:
                    self._selected = True
                    self.setBrush(self.selected_brush)
                    self.setPen(self.red_pen)
                else:
                    self._selected = False
                    self.setBrush(self.enabled_brush)
                    self.setPen(self.invisible_pen)

            self._detector_selector.selection_changed()

    def place_label(self, rect):
        # FIXMe: placement should be done differently, so that flipping the text leaves it in the same place.
        x_center = 0.5 * (rect.left() + rect.right()
                          ) - 0.5 * self._label.boundingRect().width()
        y_center = 0.5 * (rect.bottom() + rect.top(
        )) - 0.5 * self._label.boundingRect().height() + self.length
        self._label.setPos(x_center, y_center)
Exemple #35
0
    textItem.setHtml(
        '<font color="white"><b>Stickman</b>'
        "<p>"
        "Tell the stickman what to do!"
        "</p>"
        "<p><i>"
        '<li>Press <font color="purple">J</font> to make the stickman jump.</li>'
        '<li>Press <font color="purple">D</font> to make the stickman dance.</li>'
        '<li>Press <font color="purple">C</font> to make him chill out.</li>'
        '<li>When you are done, press <font color="purple">Escape</font>.</li>'
        "</i></p>"
        "<p>If he is unlucky, the stickman will get struck by lightning, and never jump, dance or chill out again."
        "</p></font>"
    )

    w = textItem.boundingRect().width()
    stickManBoundingRect = stickMan.mapToScene(stickMan.boundingRect()).boundingRect()
    textItem.setPos(-w / 2.0, stickManBoundingRect.bottom() + 25.0)

    scene = QGraphicsScene()
    scene.addItem(stickMan)
    scene.addItem(textItem)
    scene.setBackgroundBrush(Qt.black)

    view = GraphicsView()
    view.setRenderHints(QPainter.Antialiasing)
    view.setTransformationAnchor(QGraphicsView.NoAnchor)
    view.setScene(scene)
    view.show()
    view.setFocus()
Exemple #36
0
class Node(QGraphicsRectItem):
    class io(QGraphicsRectItem):
        class BezierCurve(QGraphicsPathItem):
            def __init__(self, iostart=None, ioend=None):
                super().__init__()

                self.setEnabled(
                    False
                )  # Make it ignore events. Links can't be interacted with.

                self.iostart = iostart
                self.ioend = ioend

                if iostart is not None and ioend is not None:
                    self.update()
                else:
                    self.update(QPointF(0, 0))

            def update(self, pos=None):
                path = QPainterPath()

                if pos is not None:
                    if self.ioend is None:
                        startpos = self.iostart.pos(
                        ) + self.iostart.parent.pos()
                        endpos = pos
                    elif self.iostart is None:
                        startpos = pos
                        endpos = self.ioend.pos() + self.ioend.parent.pos()
                else:
                    startpos = self.iostart.pos() + self.iostart.parent.pos()
                    endpos = self.ioend.pos() + self.ioend.parent.pos()

                controlpoint = QPointF(abs((endpos - startpos).x()) * 0.8, 0)

                path.moveTo(startpos)
                path.cubicTo(startpos + controlpoint, endpos - controlpoint,
                             endpos)

                self.setPath(path)

        def __init__(self, parent, index, iotype, iodir):
            self.parent = parent
            self.index = index
            self.iotype = iotype
            self.iodir = iodir
            super().__init__(-8, -8, 16, 16,
                             self.parent)  # Size of io-boxes is 16x16

            self.setAcceptHoverEvents(True)

            self.iobrush = QBrush(QColor(70, 70, 70, 255))
            self.setBrush(self.iobrush)

            self.newbezier = None  # Variable for temporary storage of bezier curve while it's still being dragged
            self.bezier = []

        def mousePressEvent(self, event):
            if event.button() == Qt.LeftButton:
                if self.iodir == "output":
                    self.newbezier = Node.io.BezierCurve(self, None)
                elif self.iodir == "input":
                    self.newbezier = Node.io.BezierCurve(None, self)

                if self.newbezier is not None:
                    self.newbezier.update(
                        QPointF(event.pos() + self.pos() + self.parent.pos()))

                self.parent.parent.scene.addItem(self.newbezier)
            elif event.button() == Qt.RightButton:
                self.delAllBezier()

        def mouseMoveEvent(self, event):
            if self.newbezier is not None:
                self.newbezier.update(
                    QPointF(event.pos() + self.pos() + self.parent.pos()))

        def mouseReleaseEvent(self, event):
            if self.newbezier is not None:
                self.parent.parent.scene.removeItem(self.newbezier)
            self.newbezier = None

            # Find out if an io box lies under the cursor
            pos = event.pos() + self.pos() + self.parent.pos()
            pos = self.parent.parent.mapFromScene(pos)
            target = self.parent.parent.itemAt(pos.x(), pos.y())

            # If io box is found, spawn a bezier curve
            if target is None:
                if self.iodir == "output":
                    ns = NodeSelector(self.parent.parent.modman,
                                      modfilter={
                                          "type": {
                                              "type": self.iotype,
                                              "dir": "input"
                                          }
                                      })
                elif self.iodir == "input":
                    ns = NodeSelector(self.parent.parent.modman,
                                      modfilter={
                                          "type": {
                                              "type": self.iotype,
                                              "dir": "output"
                                          }
                                      })
                if ns.exec():
                    if issubclass(ns.data["node"], baseModule.BaseNode):
                        newNode = Node(self.parent.parent, ns.data["node"])
                        newNode.setPos(event.pos() + self.pos() +
                                       self.parent.pos())
                        self.parent.parent.scene.addItem(newNode)
                        if self.iodir == "output":
                            target = newNode.inputIO[ns.data["pin"]]
                        elif self.iodir == "input":
                            target = newNode.outputIO[ns.data["pin"]]

            if target is not None and isinstance(target, Node.io):
                bezier = None
                if self.iodir == "output" and target.iodir == "input" and (
                        self.iotype == target.iotype or not self.iotype
                        or not target.iotype):
                    bezier = Node.io.BezierCurve(self, target)
                    if not self.iotype == "exec":
                        target.delAllBezier()
                    elif self.iotype == "exec":
                        if len(self.bezier) >= 1:
                            self.delAllBezier()
                elif self.iodir == "input" and target.iodir == "output" and (
                        self.iotype == target.iotype or not self.iotype
                        or not target.iotype):
                    bezier = Node.io.BezierCurve(target, self)
                    if not self.iotype == "exec":
                        self.delAllBezier()
                    elif self.iotype == "exec":
                        if len(target.bezier) >= 1:
                            target.delAllBezier()

                if bezier is not None:
                    self.bezier.append(bezier)
                    target.bezier.append(bezier)

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

        def hoverEnterEvent(self, event):
            self.parent.setPen(
                QPen(QColor("black"))
            )  # For some f*****g reason QGraphicsSceneHoverEvents can't be accepted, so this dirty workaround has to be used...
            self.setPen(QPen(QColor("yellow")))

        def hoverLeaveEvent(self, event):
            self.parent.setPen(QPen(QColor("yellow")))  # See above
            self.setPen(QPen(QColor("black")))

        def updateBezier(self):
            for bezier in self.bezier:
                bezier.update()

        def delAllBezier(self):
            beziercpy = self.bezier[:]
            for bezier in beziercpy:
                bezier.iostart.bezier.remove(bezier)
                bezier.ioend.bezier.remove(bezier)
                self.parent.parent.scene.removeItem(bezier)

    def __init__(self, parent, nodedata=None, id=None):
        if nodedata is None:
            raise ValueError("Nodetype must not be 'None'")

        self.nodedata = nodedata

        self.parent = parent
        self.width = 32
        self.height = 0
        super().__init__(-self.width / 2, -self.height / 2, self.width,
                         self.height)

        self.setAcceptHoverEvents(True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)

        self.extraNodeData = {}

        if id is not None:
            self.id = id
        else:
            self.id = uuid.uuid4().hex  # Random ID to identify node

        self.nodebrush = QBrush(QColor(100, 100, 100, 255))
        self.setBrush(self.nodebrush)

        # Node Title
        self.nodetitle = self.nodedata.name
        self.nodetitleTextItem = QGraphicsTextItem(self.nodetitle, self)
        self.width = max(self.width,
                         self.nodetitleTextItem.boundingRect().width())
        self.height += self.nodetitleTextItem.boundingRect().height()

        # Create all the text items for the IO
        self.inputTextItems = []
        self.outputTextItems = []
        for i in range(
                max(len(self.nodedata.inputDefs),
                    len(self.nodedata.outputDefs))):
            linewidth = 0
            lineheight = 0
            try:
                self.inputTextItems.append(
                    QGraphicsTextItem(self.nodedata.inputDefs[i][0], self))
                linewidth += self.inputTextItems[i].boundingRect().width()
                lineheight = max(
                    lineheight, self.inputTextItems[i].boundingRect().height())
            except IndexError:
                pass

            try:
                self.outputTextItems.append(
                    QGraphicsTextItem(self.nodedata.outputDefs[i][0], self))
                linewidth += self.outputTextItems[i].boundingRect().width()
                lineheight = max(
                    lineheight,
                    self.outputTextItems[i].boundingRect().height())
            except IndexError:
                pass

            linewidth += 12  # Keep atleast 12px distance between the input and output text
            self.width = max(self.width, linewidth)
            self.height += lineheight

        # Set correct positions for all text items
        self.nodetitleTextItem.setPos(-self.width / 2, -self.height / 2)

        self.inputIO = []
        heightPointer = 0
        for i in range(
                max(len(self.nodedata.inputDefs),
                    len(self.nodedata.outputDefs))):
            try:
                self.inputTextItems[i].setPos(
                    -self.width / 2, -self.height / 2 +
                    self.nodetitleTextItem.boundingRect().height() +
                    heightPointer)
                heightPointer += self.inputTextItems[i].boundingRect().height()

                newinput = Node.io(self, i, self.nodedata.inputDefs[i][1],
                                   "input")
                self.inputIO.append(newinput)
                newinput.setPos(
                    -self.width / 2 - newinput.rect().width() / 2,
                    -self.height / 2 + heightPointer +
                    self.inputTextItems[i].boundingRect().height() / 2)

            except IndexError:
                pass

        self.outputIO = []
        heightPointer = 0
        for i in range(
                max(len(self.nodedata.inputDefs),
                    len(self.nodedata.outputDefs))):
            try:
                self.outputTextItems[i].setPos(
                    self.width / 2 -
                    self.outputTextItems[i].boundingRect().width(),
                    -self.height / 2 +
                    self.nodetitleTextItem.boundingRect().height() +
                    heightPointer)
                heightPointer += self.outputTextItems[i].boundingRect().height(
                )

                newoutput = Node.io(self, i, self.nodedata.outputDefs[i][1],
                                    "output")
                self.outputIO.append(newoutput)
                newoutput.setPos(
                    self.width / 2 + newoutput.rect().width() / 2,
                    -self.height / 2 + heightPointer +
                    self.outputTextItems[i].boundingRect().height() / 2)

            except IndexError:
                pass

        # Set rect to correct size
        self.setRect(-self.width / 2, -self.height / 2, self.width,
                     self.height)

        # Additional stuff
        self.setFlag(QGraphicsItem.ItemIsMovable, True)

    def delete(self):
        for io in self.inputIO + self.outputIO:
            io.delAllBezier()
            io.parent = None
            io.bezier = None

        del self.inputIO
        del self.outputIO

    def mouseMoveEvent(self, event):
        super().mouseMoveEvent(event)

        for io in self.inputIO + self.outputIO:
            io.updateBezier()

    def hoverEnterEvent(self, event):
        self.setPen(QPen(QColor("yellow")))

    def hoverLeaveEvent(self, event):
        self.setPen(QPen(QColor("black")))
Exemple #37
0
class TextInputWidget(QGraphicsObject):

    input_entered = pyqtSignal(str)
    input_cancelled = pyqtSignal(str)
    font = QFont('monospace', 16)

    def __init__(self,
                 mode: str = 'number',
                 label: str = '',
                 getter=None,
                 setter=None,
                 parser=str,
                 validator=None,
                 parent: Optional[QGraphicsItem] = None):
        QGraphicsObject.__init__(self, parent)
        self.getter: Callable[[], str] = getter
        self.setter: Callable[[str], None] = setter
        self.parser: Callable[[str], Any] = parser
        self.validator: Callable[[Any], bool] = validator
        self.accept_button = Button("btn_accept", "Accept", parent=self)
        self.accept_button.set_base_color([ButtonColor.GREEN])
        self.accept_button.clicked.connect(self.handle_input_accepted)
        self.cancel_button = Button("btn_cancel", "Cancel", parent=self)
        self.cancel_button.set_base_color([ButtonColor.RED])
        self.cancel_button.clicked.connect(
            lambda: self.input_cancelled.emit(self.text_field.toPlainText()))
        self.accept_button.set_height(12)
        self.cancel_button.set_height(12)
        self.hor_padding = 2
        self.background_rect = QGraphicsRectItem(parent=self)
        self.background_rect.setBrush(QBrush(QColor(50, 50, 50, 200)))
        self.text_field = NumberInputItem(self)
        self.text_field.setFont(self.font)
        self.text_field.setTextInteractionFlags(Qt.TextEditable)
        self.text_field.setDefaultTextColor(Qt.white)
        self.text_field.text_changed.connect(self.adjust_layout)
        self.text_field.set_is_number_mode(mode == 'number')
        if self.getter is not None:
            self.text_field.setPlainText(str(self.getter()))
            self.adjust_layout()
        self.text_field.accepted.connect(
            lambda: self.accept_button.click_button(artificial_emit=True))
        self.text_field.cancelled.connect(
            lambda: self.cancel_button.click_button(artificial_emit=True))
        self.text_label = QGraphicsTextItem(self)
        self.text_label.setFont(self.font)
        self.text_label.setPlainText(label)
        self.text_label.setDefaultTextColor(Qt.white)
        self.setVisible(False)

    def paint(self,
              painter: QPainter,
              option: QStyleOptionGraphicsItem,
              widget: Optional[QWidget] = ...) -> None:
        pass

    def boundingRect(self) -> QRectF:
        return self.background_rect.boundingRect().united(self.accept_button.boundingRect())\
            .united(self.cancel_button.boundingRect())

    def adjust_layout(self):
        self.accept_button.fit_to_contents()
        self.cancel_button.fit_to_contents()
        total_width = 3 * self.hor_padding + self.text_field.boundingRect().width() \
                      + self.text_label.boundingRect().width()
        total_width = max(
            total_width,
            3 * self.hor_padding + self.accept_button.boundingRect().width() +
            self.cancel_button.boundingRect().width())
        total_height = self.text_field.boundingRect().height() + self.accept_button.boundingRect().height() \
                       + 3 * self.hor_padding
        self.background_rect.setRect(0, 0, total_width, total_height)
        self.setTransformOriginPoint(
            QPointF(0.5 * total_width, 0.5 * total_height))
        self.text_label.setPos(-0.5 * total_width + self.hor_padding,
                               -0.5 * total_height + self.hor_padding)
        self.text_field.setPos(
            self.hor_padding + self.text_label.pos().x() +
            self.text_label.boundingRect().width(),
            self.text_label.pos().y())
        self.background_rect.setPos(-0.5 * total_width, -0.5 * total_height)
        self.accept_button.set_width(
            (total_width - 3 * self.hor_padding) * 0.5)
        self.cancel_button.set_width(
            (total_width - 3 * self.hor_padding) * 0.5)
        self.accept_button.setPos(-0.5 * total_width + self.hor_padding,
                                  2 * self.hor_padding)
        self.cancel_button.setPos(self.accept_button.pos() + QPointF(
            self.hor_padding + self.accept_button.boundingRect().width(), 0.0))
        self.accept_button.set_disabled(
            len(self.text_field.toPlainText()) == 0)
        if self.validator is not None:
            try:
                value = self.parser(self.text_field.toPlainText())
                is_valid = self.validator(value)
            except ValueError:
                is_valid = False
            self.text_field.set_is_valid(is_valid)
            self.accept_button.set_disabled(not is_valid)
        self.update()

    def get_value(self) -> str:
        return self.text_field.toPlainText()

    def set_value(self, text: str):
        self.text_field.setPlainText(text)
        self.adjust_layout()
        self.set_focus()

    def set_focus(self):
        self.text_field.setFocus(Qt.PopupFocusReason)
        cursor = self.text_field.textCursor()
        cursor.movePosition(QTextCursor.EndOfLine)
        self.text_field.setTextCursor(cursor)

    def set_getter_setter_parser_validator(self, getter: Callable[[], Any],
                                           setter: Callable[[Any], None],
                                           parser: Callable[[str], Any],
                                           validator: Callable[[Any], bool]):
        self.getter = getter
        self.setter = setter
        self.parser = parser
        self.validator = validator
        if self.getter is not None:
            self.text_field.setPlainText(str(self.getter()))
            self.adjust_layout()

    def set_label(self, label: str):
        self.text_label.setPlainText(label)
        self.adjust_layout()

    def handle_input_accepted(self):
        self.setter(self.parser(self.text_field.toPlainText()))
        self.input_entered.emit(self.text_field.toPlainText())

    def handle_input_cancelled(self):
        self.input_cancelled.emit(str(self.getter()))
Exemple #38
0
class Block(QGraphicsRectItem):
    """
        Entity-block with text & four connection ports
    """
    def __init__(self, name='Untitled', parent=None):
        super(Block, self).__init__(None)
        self.parent = parent

        w = 60.0
        h = 40.0

        self.__base_color = QColor(158, 94, 155)

        # Properties of the rectangle:
        self.setPen(QtGui.QPen(self.__base_color, 2))
        # self.setPen(QtGui.QPen(QtCore.Qt.blue, 2))
        self.setBrush(QtGui.QBrush(self.__base_color))
        self.setFlags(self.ItemIsSelectable | self.ItemIsMovable)
        self.setCursor(QCursor(QtCore.Qt.PointingHandCursor))

        # Label:
        self.label = QGraphicsTextItem(name, self)
        self.label.setFont(QFont())
        self.name = name

        # Create corner for resize:
        self.sizer = HandleItem(self)
        self.sizer.setPos(w, h)
        self.sizer.posChangeCallbacks.append(
            self.changeSize)  # Connect the callback

        self.sizer.setFlag(self.sizer.ItemIsSelectable, True)

        # Inputs and outputs of the block:
        self.ports = []
        self.ports.append(PortItem('a', self))
        self.ports.append(PortItem('b', self))
        self.ports.append(PortItem('c', self))
        self.ports.append(PortItem('d', self))

        # Update size:
        self.changeSize(w, h)

    def get_text(self):
        return self.label.toPlainText()

    def get_random_port(self):
        i = random.randint(0, len(self.ports) - 1)
        if i in range(0, 5):
            return self.ports[i]

    def delete(self):
        msg = QMessageBox()

        msg.setIcon(QMessageBox.Question)
        msg.setText("Вы действительно хотите удалить блок?")
        msg.setInformativeText("Это действие нельзя отменить")
        msg.setWindowTitle("Подтвердите действие")
        msg.setDetailedText("При удалении блока удалятся все его соединения!")

        msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)

        confirm = msg.exec_()

        if confirm == QMessageBox.Ok:
            self.parent.remove_node(self)

    def edit_parameters(self):
        text, ok = QInputDialog.getText(None,
                                        'Параметры',
                                        'Текст блока:',
                                        text=self.label.toPlainText())
        if ok:
            self.label.setPlainText(text)

    def contextMenuEvent(self, event):
        menu = QMenu()
        action_delete = menu.addAction('Удалить')
        action_params = menu.addAction('Параметры')
        action_delete.triggered.connect(self.delete)
        action_params.triggered.connect(self.edit_parameters)
        menu.exec_(event.screenPos())

    def changeSize(self, w, h):
        """ Resize block function """
        # Limit the block size:

        metric = QFontMetrics(self.label.font())
        width = metric.width(self.name)
        height = metric.height()

        if h < height + 5:
            h = height + 5
        if w < width + 5:
            w = width + 5
        self.setRect(0.0, 0.0, w, h)
        # center label:
        rect = self.label.boundingRect()
        lw, lh = rect.width(), rect.height()
        lx = (w - lw) / 2
        ly = (h - lh) / 2
        self.label.setPos(lx, ly)
        # Update port positions:
        self.ports[0].setPos(0, h / 2)
        self.ports[1].setPos(w / 2, 0)
        self.ports[2].setPos(w, h / 2)
        self.ports[3].setPos(w / 2, h)
        return w, h