Пример #1
0
    def __init__(self,
                 text=None,
                 datatype: DataType = None,
                 parent: QGraphicsItem = None):
        super().__init__(parent)

        self.setFlag(
            self.ItemSendsScenePositionChanges)  # To enable edge adjusting
        self.setFlag(self.ItemIsSelectable)
        self.setFlag(
            self.ItemHasNoContents)  # Drawing occurs using child items

        self.edges = set()
        """Edges attached to this connection. To change this set use `Connection`'s methods: attach, detach, detachAll.
        """

        self._text_item = TextLineItem(text or "Connection", self)
        self._stem_item = QGraphicsLineItem(self)

        self._trigger_item = Trigger(self)

        self._datatype = datatype or DataType.Unknown
        self._is_multiple = False
        """Determines if the connection can have multiple edges coming out of it.  
        By default, it is False for Input and True for Output.
        """

        self._approved_selection = True
        """Connection is not selectable from outside sources. This flag is set by some internal methods to indicate that
        a selection is legitimate."""

        self.hideText()
        self.styleChange()
        self.paletteChange()
Пример #2
0
    def __init__(self,
                 parent,
                 color,
                 text_color,
                 text_start="",
                 margins=(0, 0, 0, 0),
                 dp=1,
                 is_upload=False):
        self._parent = parent
        self._color = color
        self._text_color = text_color
        self._text_start = text_start
        self._left, self._top, self._right, self._bottom = margins
        self._dp = dp
        self._is_upload = is_upload

        self._line = QGraphicsLineItem(self._parent)
        self._line.setZValue(12)
        pen = QPen(self._color)
        pen.setWidth(1)
        pen.setStyle(Qt.DashLine)
        self._line.setPen(pen)

        if not self._is_upload:
            self._text_item = QGraphicsTextItem(self._parent)
            self._text_item.setZValue(11)
            self._text_item.setDefaultTextColor(self._text_color)
            font = self._text_item.font()
            font_size = 10 * self._dp
            if font_size > 0:
                self._text_item.setFont(QFont(font.family(), font_size))
Пример #3
0
 def __init__(self, entity_child, entity_base, parent=None):
     QGraphicsLineItem.__init__(self, parent)
     self.child = entity_child
     self.parent = entity_base
     self.arrowHead = QtGui.QPolygonF()
     self.arrowSize = 10.0
     self.line_width = 5
     self.line_color = QtGui.QColor('black')
     self.setPen(
         QtGui.QPen(self.line_color, self.line_width, QtCore.Qt.SolidLine,
                    QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
     self.setZValue(-1000)  # hide arrow behind all widgets ??
    def create_diagonal_lines(self):
        left_top_right_bottom = QGraphicsLineItem(
            0, 0, self.model.monitor.screen_width,
            self.model.monitor.screen_height)
        right_top_left_bottom = QGraphicsLineItem(
            self.model.monitor.screen_width, 0, 0,
            self.model.monitor.screen_height)

        self.diagonal_lines_layer.add_to_layer(left_top_right_bottom)
        self.diagonal_lines_layer.add_to_layer(right_top_left_bottom)

        self.graphics_scene.addItem(left_top_right_bottom)
        self.graphics_scene.addItem(right_top_left_bottom)
Пример #5
0
    def overlay_line(
        self,
        color: int,
        line_width: int,
        x1: int,
        y1: int,
        x2: int,
        y2: int,
        timeout: int,
    ):
        pen = QPen(decode_color(color))
        pen.setWidthF(max(1.0, line_width / 10))

        gfx = QGraphicsLineItem(x1, y1, x2, y2)
        gfx.setPen(pen)

        self._finalize_gfx(gfx, timeout)
Пример #6
0
    def _setup_inputs(self):
        for inp in self._inputs:
            self.scene().removeItem(inp[0])
            self.scene().removeItem(inp[1])

        self._inputs = list()

        n = self.desc.num_inputs

        for i in range(n):
            pos = _pin_pos(self.rect(), 0, (2 * i + 1) / (n * 2))

            pin = Pin(self, self.desc.get_pin(f'in{i}'))
            pin.setPos(pos)

            pen = QPen(Qt.black, 2, c=Qt.RoundCap)
            r = self.rect()
            yy = r.height() * (2 * i + 1) / (n * 2)
            ext = QGraphicsLineItem(pos.x() + Pin._SIZE.width() / 2,
                                    pos.y() + Pin._SIZE.height() / 2,
                                    r.width() / 3,
                                    pos.y() + Pin._SIZE.height() / 2, self)
            ext.setPen(pen)
            ext.setFlag(QGraphicsItem.ItemStacksBehindParent)
            self._inputs.append((pin, ext))
Пример #7
0
def init_visual_scene_axis():
    """
    Create two lines that represent the axis of the scene
    :return: the two Items that are the lines
    """
    # axis.append(QGraphicsLineItem(QPointF(-500, 0), QPointF(500, 0)))
    # axis.append(QGraphicsLineItem(QPointF(0, 500), QPointF(0, -500)))

    hor_line = QGraphicsLineItem(-500, 0, 500, 0)
    hor_line.setPen(initialize_qpen(Qt.green, 1))

    vert_line = QGraphicsLineItem(0, 500, 0, -500)
    vert_line.setPen(initialize_qpen(Qt.green, 1))

    return [hor_line, vert_line]
Пример #8
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFlag(self.ItemIsMovable)
        self.setFlag(self.ItemIsSelectable)

        # Default size and text
        self._size = QSizeF(0, 115)

        self._body_item = QGraphicsPathItem(self)
        self._title_item = TextLineItem("Node", self)
        self._divider = QGraphicsLineItem(self)
        self._description_item = TextRectItem("No description", self)

        # Inputs and outputs
        self.inputs = []
        self.outputs = []
        self.messages = SortedList(key=lambda item: item.severity())

        self._config_widget = None

        # Set proper style and color for the item
        self.styleChange()
        self.paletteChange()
Пример #9
0
 def draw_2d(self):
     self.graphicsScene.clear()
     point, line = [], []
     point.append((0, 0))
     for i in range(1, 4):
         point.append(
             (point[i - 1][0] +
              (lengths[i - 1] * math.cos(np.deg2rad(-sum(angles[:i])))),
              point[i - 1][1] +
              (lengths[i - 1] * math.sin(np.deg2rad(-sum(angles[:i]))))))
         line.append(
             QGraphicsLineItem(point[i - 1][0], point[i - 1][1],
                               point[i][0], point[i][1]))
         self.graphicsScene.addItem(line[i - 1])
     self.label_5.setText("[" + str(round(point[3][0], PRECISION)) + ", " +
                          str(round(-point[3][1], PRECISION)) + "]")
Пример #10
0
    def __init__(self, simulator, desc):
        super().__init__(simulator, desc)

        self.setRect(QRectF(QPoint(), self._SIZE))

        self._inputs = list()

        r = self.rect()

        pin = Pin(self, desc.get_pin('out'))
        pin.setPos(_pin_pos(self.rect(), 1, 0.5))
        pin.setZValue(1)

        pen = QPen(Qt.black, 2, c=Qt.RoundCap)
        ext1 = QGraphicsLineItem(r.right() + _EXT_LENGTH,
                                 r.height() / 2, r.right(),
                                 r.height() / 2, self)
        ext1.setPen(pen)
        ext1.setFlag(QGraphicsItem.ItemStacksBehindParent)

        self._setup_inputs()
Пример #11
0
class MainView(QGraphicsView):
    def __init__(self, scene):
        QGraphicsView.__init__(self, scene)
        self.setMouseTracking(True)
        self.setFrameShape(QFrame.NoFrame)
        self.padding_h = 60
        self.title_h = 25
        self.scene = scene
        self.gray_pen = QPen(QColor(224, 224, 224), 1)
        self.timer_id = 0
        self.price_model = PriceModel()
        self.secondary_num = 1

    def mouseMoveEvent(self, event):
        x = event.pos().x()
        y = event.pos().y()
        if (x < self.width() - self.padding_h and x > self.padding_h) \
                and ((y < self.price_area_height + self.title_h
                     and y > self.title_h)
                     or (y < (self.height() - self.title_h) and
                     y > self.price_area_height + self.title_h * 2)):
            self.pos_h_line.setVisible(True)
            self.pos_v_line.setVisible(True)
            self.pos_h_line.setY(y)
            self.pos_v_line.setX(x)

            if y > self.title_h and y < self.price_area_height + self.title_h:
                self.price.setVisible(True)
                self.rov.setVisible(True)
                self.price.setY(y - 7)
                self.rov.setY(y - 7)

                price = round(
                    (self.price_model.max_y - (y - self.title_h) /
                     self.price_area_height * self.price_model.diff_y), 2)
                rov = round((price - self.price_model.yestoday_close) /
                            self.price_model.yestoday_close * 100, 2)
                price = "{:.2f}".format(price)
                rov = "{:.2f}%".format(rov)
                self.price.set_text(price)
                self.rov.set_text(rov)
            if y > self.vol.y() and y < self.vol.y() + self.vol.size.height():
                vol = int(self.price_model.max_vol - (y - self.vol.y()) /
                          self.vol.size.height() * self.price_model.max_vol)
                self.vol_l.setVisible(True)
                self.vol_r.setVisible(True)
                self.vol_l.setY(y - 7)
                self.vol_r.setY(y - 7)
                self.vol_l.set_text(str(vol))
                self.vol_r.set_text(str(vol))
        else:
            self.pos_h_line.setVisible(False)
            self.pos_v_line.setVisible(False)
            self.price.setVisible(False)
            self.rov.setVisible(False)
            self.vol_l.setVisible(False)
            self.vol_r.setVisible(False)

    def resizeEvent(self, event):
        self.scene.setSceneRect(0, 0, self.width(), self.height())
        self.price_area_height = (self.height() - self.title_h) * 3 / 5
        self.secondary_area_h = self.height() - self.price_area_height - \
            self.title_h * (self.secondary_num + 2)
        self.draw()
        if self.timer_id:
            self.killTimer(self.timer_id)
            self.timer_id = 0
        self.timer_id = self.startTimer(100)

    # def timerEvent(self, event):
    # self.draw()

    def draw(self):
        self.scene.clear()

        # 画标题
        self.title = self.scene.addText('掌趣科技')
        self.title.setPos(4, 0)

        # 画补横线
        self.scene.addLine(0, self.title_h, self.padding_h, self.title_h,
                           self.gray_pen)
        self.scene.addLine(self.width() - self.padding_h, self.title_h,
                           self.width(), self.title_h, self.gray_pen)
        self.scene.addLine(0, self.price_area_height + self.title_h,
                           self.padding_h,
                           self.price_area_height + self.title_h,
                           self.gray_pen)
        self.scene.addLine(self.width() - self.padding_h,
                           self.price_area_height + self.title_h, self.width(),
                           self.price_area_height + self.title_h,
                           self.gray_pen)

        # 画背景价格区域背景
        self.price_area_background = \
            CrossLineBackground(QSizeF(self.width() - self.padding_h * 2,
                                       self.price_area_height), self.gray_pen)
        self.price_area_background.setPos(self.padding_h, self.title_h)

        # 画价格曲线
        pen = QPen(QColor(33, 150, 243))
        self.price_area = PriceLine(
            QSizeF(self.width() - self.padding_h * 2 - 2,
                   self.price_area_height), pen, self.price_model)
        self.price_area.setPos(self.padding_h + 1, self.title_h)

        # 画价格区域左右Y轴
        self.price_yaxis = PriceYaxis(
            QSizeF(self.width(), self.price_area_height), self.price_model)
        self.price_yaxis.setPos(0, self.title_h)

        # 画游标十字线,以及左右Y轴X轴显示
        pos_pen = QPen(QColor(117, 117, 117), 1, Qt.DashDotLine)
        self.pos_h_line = QGraphicsLineItem(0, 0,
                                            self.width() - self.padding_h * 2,
                                            0)
        self.pos_h_line.setPen(pos_pen)
        self.pos_h_line.setPos(self.padding_h, self.title_h)
        self.pos_v_line = QGraphicsLineItem(0, 0, 0,
                                            self.height() - self.title_h * 2)
        self.pos_v_line.setPen(pos_pen)
        self.pos_v_line.setPos(self.padding_h, self.title_h)
        self.pos_h_line.setVisible(False)
        self.pos_v_line.setVisible(False)
        self.price = PosText(QSizeF(self.padding_h - 2, 15),
                             str(self.price_model.yestoday_close),
                             Qt.AlignRight)
        self.price.setPos(1, (self.height() - self.title_h) * 3 / 10 - 7.5)
        self.price.setVisible(False)
        self.rov = PosText(QSizeF(self.padding_h - 2, 15), '0.00%',
                           Qt.AlignLeft)
        self.rov.setPos(self.width() - self.padding_h + 1,
                        (self.height() - self.title_h) * 3 / 10 - 7.5)
        self.rov.setVisible(False)
        self.vol_l = PosText(QSizeF(self.padding_h - 2, 15), '0',
                             Qt.AlignRight)
        self.vol_l.setPos(1, (self.height() - self.title_h) * 3 / 10 - 7.5)
        self.vol_l.setVisible(False)
        self.vol_r = PosText(QSizeF(self.padding_h - 2, 15), '0', Qt.AlignLeft)
        self.vol_r.setPos(self.width() - self.padding_h + 1,
                          (self.height() - self.title_h) * 3 / 10 - 7.5)
        self.vol_r.setVisible(False)

        # 画副图区域背景
        self.second_area_background = \
            CrossLineBackground(QSizeF(self.width() - self.padding_h * 2,
                                       self.height() - self.price_area_height
                                       - self.title_h * 3), self.gray_pen, 2)
        self.second_area_background.setPos(
            self.padding_h, self.title_h * 2 + self.price_area_height)

        # 画副标题一
        self.title1 = self.scene.addText('成交量')
        self.title1.setPos(4, self.title_h + self.price_area_height)

        # 画副图分割线
        self.scene.addLine(0, self.title_h * 2 + self.price_area_height,
                           self.width(),
                           self.title_h * 2 + self.price_area_height,
                           self.gray_pen)
        self.scene.addLine(0,
                           self.height() - self.title_h, self.width(),
                           self.height() - self.title_h, self.gray_pen)

        # 画副图一
        self.vol = VolumeBar(
            QSizeF(self.width() - self.padding_h * 2 - 2,
                   self.height() - self.price_area_height - self.title_h * 3),
            self.price_model)
        self.vol.setPos(self.padding_h + 1,
                        self.title_h * 2 + self.price_area_height)

        # 画副图区域左右Y轴
        self.second_yaxis = SecondYaxis(
            QSizeF(self.width(),
                   self.height() - self.title_h * 3 - self.price_area_height),
            self.price_model.max_vol, 0)
        self.second_yaxis.setPos(0, self.title_h * 2 + self.price_area_height)

        self.scene.addItem(self.price_area_background)
        self.scene.addItem(self.price_area)
        self.scene.addItem(self.price_yaxis)
        self.scene.addItem(self.second_area_background)
        self.scene.addItem(self.vol)
        self.scene.addItem(self.second_yaxis)
        self.scene.addItem(self.pos_h_line)
        self.scene.addItem(self.pos_v_line)
        self.scene.addItem(self.price)
        self.scene.addItem(self.rov)
        self.scene.addItem(self.vol_l)
        self.scene.addItem(self.vol_r)
Пример #12
0
    def _create_line_indicator(self, addr, item_map, color=Qt.yellow, show_frontier=False, z=None, z_frontier=None):
        """
        Generate a cursor at a given address.
        """
        pos_x = self._get_pos_from_addr(addr)
        if pos_x is None:
            return

        pen = QPen(color)
        brush = QBrush(color)
        height = self.height

        tri_width = 7
        tri_height = 4

        pos_x = int(pos_x - tri_width / 2)  # Center drawing
        center = pos_x + int(tri_width / 2)
        pos_y = 0
        frontier_width = int(0.15 * max(self.width, self.height))

        if show_frontier:
            # Draw frontier gradients
            r = QRectF(center - frontier_width, pos_y, frontier_width, height)
            bg = QLinearGradient(r.topLeft(), r.topRight())
            color = Qt.red
            top_color = QColor(color)
            top_color.setAlpha(0)
            bg.setColorAt(0, top_color)
            bottom_color = QColor(color)
            bottom_color.setAlpha(180)
            bg.setColorAt(1, bottom_color)

            i = QGraphicsRectItem(r, parent=self)
            i.setPen(Qt.NoPen)
            i.setBrush(bg)
            if z_frontier is not None:
                i.setZValue(z_frontier)
            item_map.append(i)

            r = QRectF(center, pos_y, frontier_width, height)
            bg = QLinearGradient(r.topLeft(), r.topRight())
            color = Qt.blue
            top_color = QColor(color)
            bg.setColorAt(0, top_color)
            bottom_color = QColor(color)
            bottom_color.setAlpha(0)
            bg.setColorAt(1, bottom_color)

            i = QGraphicsRectItem(r, parent=self)
            i.setPen(Qt.NoPen)
            i.setBrush(bg)
            if z_frontier is not None:
                i.setZValue(z_frontier)
            item_map.append(i)

        # Draw line
        i = QGraphicsLineItem(center, 0, center, height, parent=self)
        i.setPen(pen)
        if z is not None:
            i.setZValue(z)
        item_map.append(i)

        # Draw top and bottom triangles
        t = QPolygonF()
        t.append(QPointF(pos_x, pos_y))
        t.append(QPointF(pos_x + tri_width - 1, pos_y))
        t.append(QPointF(center, pos_y + tri_height - 1))
        t.append(QPointF(pos_x, pos_y))

        pos_y += height - 1
        b = QPolygonF()
        b.append(QPointF(pos_x, pos_y))
        b.append(QPointF(center, pos_y - tri_height + 1))
        b.append(QPointF(pos_x + tri_width - 1, pos_y))
        b.append(QPointF(pos_x, pos_y))

        for i in [QGraphicsPolygonItem(t, parent=self),
                  QGraphicsPolygonItem(b, parent=self)]:
            i.setPen(pen)
            i.setBrush(brush)
            if z is not None:
                i.setZValue(z)
            item_map.append(i)
Пример #13
0
class ScaleLine:
    def __init__(self,
                 parent,
                 color,
                 text_color,
                 text_start="",
                 margins=(0, 0, 0, 0),
                 dp=1,
                 is_upload=False):
        self._parent = parent
        self._color = color
        self._text_color = text_color
        self._text_start = text_start
        self._left, self._top, self._right, self._bottom = margins
        self._dp = dp
        self._is_upload = is_upload

        self._line = QGraphicsLineItem(self._parent)
        self._line.setZValue(12)
        pen = QPen(self._color)
        pen.setWidth(1)
        pen.setStyle(Qt.DashLine)
        self._line.setPen(pen)

        if not self._is_upload:
            self._text_item = QGraphicsTextItem(self._parent)
            self._text_item.setZValue(11)
            self._text_item.setDefaultTextColor(self._text_color)
            font = self._text_item.font()
            font_size = 10 * self._dp
            if font_size > 0:
                self._text_item.setFont(QFont(font.family(), font_size))

    def set_line(self, max_value=0, resize=False):
        height = self._parent.size().height() + self._top + self._bottom
        shift = int(height - height / 1.1)
        y = -self._top + shift

        if not self._is_upload:
            value = 0
            max_value = int(max_value / 1.1)
            megabyte = 1024 * 1024
            if max_value > megabyte:
                value = "{} MB".format(round(max_value / megabyte, 1))
            elif max_value > 1024:
                max_value //= 1024
                if max_value >= 10:
                    max_value = max_value // 10 * 10
                value = "{} KB".format(max_value)
            elif max_value > 0:
                if max_value >= 10:
                    max_value = max_value // 10 * 10
                value = "{} B".format(max_value)
            scale_text =  self._text_start if not value \
                else "{}{}/s".format(self._text_start, value)

            font_height = QFontMetrics(self._text_item.font())\
                .boundingRect(scale_text).height()
            x = 10
            self._text_item.setPos(x, y - font_height - 10)
            self._text_item.setPlainText(scale_text)

        if not resize:
            return

        self._line.setLine(QLineF(0, y, self._parent.size().width() + 30, y))
Пример #14
0
    def draw(self):
        self.scene.clear()

        # 画标题
        self.title = self.scene.addText('掌趣科技')
        self.title.setPos(4, 0)

        # 画补横线
        self.scene.addLine(0, self.title_h, self.padding_h, self.title_h,
                           self.gray_pen)
        self.scene.addLine(self.width() - self.padding_h, self.title_h,
                           self.width(), self.title_h, self.gray_pen)
        self.scene.addLine(0, self.price_area_height + self.title_h,
                           self.padding_h,
                           self.price_area_height + self.title_h,
                           self.gray_pen)
        self.scene.addLine(self.width() - self.padding_h,
                           self.price_area_height + self.title_h, self.width(),
                           self.price_area_height + self.title_h,
                           self.gray_pen)

        # 画背景价格区域背景
        self.price_area_background = \
            CrossLineBackground(QSizeF(self.width() - self.padding_h * 2,
                                       self.price_area_height), self.gray_pen)
        self.price_area_background.setPos(self.padding_h, self.title_h)

        # 画价格曲线
        pen = QPen(QColor(33, 150, 243))
        self.price_area = PriceLine(
            QSizeF(self.width() - self.padding_h * 2 - 2,
                   self.price_area_height), pen, self.price_model)
        self.price_area.setPos(self.padding_h + 1, self.title_h)

        # 画价格区域左右Y轴
        self.price_yaxis = PriceYaxis(
            QSizeF(self.width(), self.price_area_height), self.price_model)
        self.price_yaxis.setPos(0, self.title_h)

        # 画游标十字线,以及左右Y轴X轴显示
        pos_pen = QPen(QColor(117, 117, 117), 1, Qt.DashDotLine)
        self.pos_h_line = QGraphicsLineItem(0, 0,
                                            self.width() - self.padding_h * 2,
                                            0)
        self.pos_h_line.setPen(pos_pen)
        self.pos_h_line.setPos(self.padding_h, self.title_h)
        self.pos_v_line = QGraphicsLineItem(0, 0, 0,
                                            self.height() - self.title_h * 2)
        self.pos_v_line.setPen(pos_pen)
        self.pos_v_line.setPos(self.padding_h, self.title_h)
        self.pos_h_line.setVisible(False)
        self.pos_v_line.setVisible(False)
        self.price = PosText(QSizeF(self.padding_h - 2, 15),
                             str(self.price_model.yestoday_close),
                             Qt.AlignRight)
        self.price.setPos(1, (self.height() - self.title_h) * 3 / 10 - 7.5)
        self.price.setVisible(False)
        self.rov = PosText(QSizeF(self.padding_h - 2, 15), '0.00%',
                           Qt.AlignLeft)
        self.rov.setPos(self.width() - self.padding_h + 1,
                        (self.height() - self.title_h) * 3 / 10 - 7.5)
        self.rov.setVisible(False)
        self.vol_l = PosText(QSizeF(self.padding_h - 2, 15), '0',
                             Qt.AlignRight)
        self.vol_l.setPos(1, (self.height() - self.title_h) * 3 / 10 - 7.5)
        self.vol_l.setVisible(False)
        self.vol_r = PosText(QSizeF(self.padding_h - 2, 15), '0', Qt.AlignLeft)
        self.vol_r.setPos(self.width() - self.padding_h + 1,
                          (self.height() - self.title_h) * 3 / 10 - 7.5)
        self.vol_r.setVisible(False)

        # 画副图区域背景
        self.second_area_background = \
            CrossLineBackground(QSizeF(self.width() - self.padding_h * 2,
                                       self.height() - self.price_area_height
                                       - self.title_h * 3), self.gray_pen, 2)
        self.second_area_background.setPos(
            self.padding_h, self.title_h * 2 + self.price_area_height)

        # 画副标题一
        self.title1 = self.scene.addText('成交量')
        self.title1.setPos(4, self.title_h + self.price_area_height)

        # 画副图分割线
        self.scene.addLine(0, self.title_h * 2 + self.price_area_height,
                           self.width(),
                           self.title_h * 2 + self.price_area_height,
                           self.gray_pen)
        self.scene.addLine(0,
                           self.height() - self.title_h, self.width(),
                           self.height() - self.title_h, self.gray_pen)

        # 画副图一
        self.vol = VolumeBar(
            QSizeF(self.width() - self.padding_h * 2 - 2,
                   self.height() - self.price_area_height - self.title_h * 3),
            self.price_model)
        self.vol.setPos(self.padding_h + 1,
                        self.title_h * 2 + self.price_area_height)

        # 画副图区域左右Y轴
        self.second_yaxis = SecondYaxis(
            QSizeF(self.width(),
                   self.height() - self.title_h * 3 - self.price_area_height),
            self.price_model.max_vol, 0)
        self.second_yaxis.setPos(0, self.title_h * 2 + self.price_area_height)

        self.scene.addItem(self.price_area_background)
        self.scene.addItem(self.price_area)
        self.scene.addItem(self.price_yaxis)
        self.scene.addItem(self.second_area_background)
        self.scene.addItem(self.vol)
        self.scene.addItem(self.second_yaxis)
        self.scene.addItem(self.pos_h_line)
        self.scene.addItem(self.pos_v_line)
        self.scene.addItem(self.price)
        self.scene.addItem(self.rov)
        self.scene.addItem(self.vol_l)
        self.scene.addItem(self.vol_r)
Пример #15
0
 def shape(self):
     path = QGraphicsLineItem.shape(self)
     path.addPolygon(self.arrowHead)
     return path
Пример #16
0
class Node(SchemeItem):
    """The main component of the graph scene.

    A node represents a single vertex of the graph, with its associated information and inputs/outputs.
    """
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFlag(self.ItemIsMovable)
        self.setFlag(self.ItemIsSelectable)

        # Default size and text
        self._size = QSizeF(0, 115)

        self._body_item = QGraphicsPathItem(self)
        self._title_item = TextLineItem("Node", self)
        self._divider = QGraphicsLineItem(self)
        self._description_item = TextRectItem("No description", self)

        # Inputs and outputs
        self.inputs = []
        self.outputs = []
        self.messages = SortedList(key=lambda item: item.severity())

        self._config_widget = None

        # Set proper style and color for the item
        self.styleChange()
        self.paletteChange()

    # Operations =======================================================================================================
    def showConnectionText(self):
        for input in self.inputs:
            input.showText()

        for output in self.outputs:
            output.showText()

    def hideConnectionText(self):
        for input in self.inputs:
            input.hideText()

        for output in self.outputs:
            output.hideText()

    # Input/output management ==========================================================================================
    def addInput(self, obj: Input):
        self.insertInput(len(self.inputs), obj)

    def insertInput(self, index, obj: Input):
        index = clamp(index, 0, len(self.inputs))
        self.inputs.insert(index, obj)

        obj.setParentItem(self)

        self._updateInputPositions()

    def removeInput(self, index):
        removed = self.inputs.pop(index)
        removed.setParentItem(None)

        self._updateInputPositions()

        return removed

    def addOutput(self, obj: Output):
        self.insertOutput(len(self.outputs), obj)

    def insertOutput(self, index, obj: Output):
        index = clamp(index, 0, len(self.outputs))
        self.outputs.insert(index, obj)

        obj.setParentItem(self)

        self._updateOutputPositions()

    def removeOutput(self, index):
        removed = self.outputs.pop(index)
        removed.setParentItem(None)

        self._updateOutputPositions()

        return removed

    # Message management ===============================================================================================
    def addMessage(self, obj: Message):
        self.messages.add(obj)
        obj.setParentItem(self)

        self._updateMessagePositions()

    def removeMessage(self, index):
        removed = self.messages.pop(index)
        removed.setParentItem(None)

        self._updateMessagePositions()

        return removed

    # Member variables =================================================================================================
    def setTitle(self, title):
        self._title_item.setText(title)

    def setDescription(self, description):
        self._description_item.setText(description)

    def setConfigWidget(self, w):
        self._config_widget = w

    def size(self):
        return self._size

    def title(self):
        return self._title_item.text()

    def description(self):
        return self._description_item.text()

    def configWidget(self):
        """Return a widget for configuring this node, or None if it does not exist."""
        return self._config_widget

    # Updating functions ===============================================================================================
    def _updateInputPositions(self):
        padding = self.style().pixelMetric(Style.NodeConnectionPadding)

        i = 0
        for item in self.inputs:
            item.setPos(0, padding * (2 * i + 1))
            i += 1

    def _updateOutputPositions(self):
        padding = self.style().pixelMetric(Style.NodeConnectionPadding)

        i = 0
        for item in self.outputs:
            item.setPos(self.size().width(), padding * (2 * i + 1))
            i += 1

    def _updateMessagePositions(self):
        padding = self.style().pixelMetric(Style.NodeMessagePadding)
        icon_size = self.style().pixelMetric(Style.MessageIconSize)

        i = 0
        for msg in self.messages:
            msg.setPos(
                0,
                self.size().height() + padding * (i + 1) + icon_size * i)
            i += 1

    # Geometry and drawing =============================================================================================
    def boundingRect(self) -> QRectF:
        frame_width = self.style().pixelMetric(Style.NodeFrameWidth)

        return QRectF(QPointF(-frame_width / 2, -frame_width / 2),
                      self.size() + QSizeF(frame_width, frame_width))

    def shape(self):
        frame_corner_radius = self.style().pixelMetric(
            Style.NodeFrameCornerRadius)

        path = QPainterPath()
        path.addRoundedRect(QRectF(QPointF(0, 0), self.size()),
                            frame_corner_radius, frame_corner_radius)

        return path

    def paint(self, painter: QPainter, option, widget=...) -> None:
        pass

    # Event handlers ===================================================================================================
    def styleChange(self):
        self.prepareGeometryChange()
        style = self.style()

        # Size and Frame
        frame_width = style.pixelMetric(Style.NodeWidth)
        self._size.setWidth(frame_width)
        self._body_item.setPen(style.framePen(self.palette()))

        path = QPainterPath()
        path.addRoundedRect(QRectF(QPointF(), self.size()),
                            style.pixelMetric(Style.NodeFrameCornerRadius),
                            style.pixelMetric(Style.NodeFrameCornerRadius))
        self._body_item.setPath(path)

        # Title item
        title_font = style.font(Style.NodeTitleFont)
        title_metrics = QFontMetricsF(title_font)

        padding = style.pixelMetric(Style.NodeFrameTextPadding)

        self._title_item.setFont(title_font)
        self._title_item.setPos(padding, padding)
        self._title_item.moveBy(0, title_metrics.capHeight())
        self._title_item.setMaximumWidth(frame_width - padding * 2)

        # Divider item
        div_margin = style.pixelMetric(Style.NodeDividerTextMargin)
        div_voffset = padding + title_metrics.capHeight(
        ) + title_metrics.descent() + div_margin

        self._divider.setLine(0, div_voffset, frame_width, div_voffset)
        self._divider.setPen(style.framePen(self.palette()))

        # Description item
        self._description_item.setFont(style.font(Style.NodeDescriptionFont))
        self._description_item.setPos(padding, div_voffset + div_margin)
        self._description_item.setFrame(
            QRectF(
                QPointF(0, 0),
                QSizeF(
                    px(frame_width) - padding * 2,
                    (px(self.size().height()) - padding) -
                    (div_voffset + padding))))

    def paletteChange(self):
        self._body_item.setPen(self.style().framePen(self.palette()))
        self._body_item.setBrush(self.palette().base())
        self._title_item.setBrush(self.palette().text())
        self._description_item.setBrush(self.palette().text())
        self._divider.setPen(self.style().framePen(self.palette()))

        self.update(self.boundingRect())

    def itemChange(self, change, value):
        if change == self.ItemSelectedHasChanged:
            selection = self.scene().selection()
            if len(selection.nodes) == 1:
                for edge in selection.edges:
                    edge.autoSelect()

            # Update selection status for all connections
            for input in self.inputs:
                input.autoSelect()

            for output in self.outputs:
                output.autoSelect()

        return super().itemChange(change, value)

    def mouseDoubleClickEvent(self, event):
        if self.configWidget() is not None:
            view = event.widget().parent()
            view.configRequested.emit(self)

    # Serialization ====================================================================================================
    def serialize(self) -> dict:
        return {
            "title": self.title(),
            "description": self.description(),
            "inputs": self.inputs,
            "outputs": self.outputs,
            "messages": list(self.messages),
            "position": inch(self.pos())
        }

    @classmethod
    def deserialize(cls, data: dict):
        obj = cls()
        obj.setTitle(data["title"])
        obj.setDescription(data["description"])
        obj.setPos(px(data["position"]))

        for i in range(len(obj.inputs)):
            obj.removeInput(0)

        for i in range(len(obj.outputs)):
            obj.removeOutput(0)

        for i in range(len(obj.messages)):
            obj.removeMessage(0)

        for input in data["inputs"]:
            obj.addInput(input)

        for output in data["outputs"]:
            obj.addOutput(output)

        for message in data["messages"]:
            obj.addMessage(message)

        return obj
Пример #17
0
    def _generate_map_items(self, **kwargs):  # pylint: disable=unused-argument
        """
        Generate the feature map items (memory region blocks, separating lines, etc).
        """
        cfb = self.instance.cfb.am_obj
        if cfb is None:
            return

        for item in self._map_items:
            self.scene().removeItem(item)
        self._map_items.clear()
        self._calculate_memory_region_offsets()

        func_color = Conf.feature_map_color_regular_function
        data_color = Conf.feature_map_color_data
        unknown_color = Conf.feature_map_color_unknown
        delimiter_color = Conf.feature_map_color_delimiter
        offset = 0
        current_region = None

        for addr, obj in cfb.ceiling_items():
            if obj.size is None:
                continue

            # Are we in a new region?
            new_region = False
            if current_region is None or not current_region.addr <= addr < current_region.addr + current_region.size:
                try:
                    current_region_addr = next(
                        self._addr_to_region.irange(maximum=addr,
                                                    reverse=True))
                except StopIteration:
                    # FIXME: it's not within any of the known regions
                    # we should fix this in the future. for now, let's make sure it does not crash
                    continue
                current_region = self._addr_to_region[current_region_addr]
                new_region = True

            if new_region:
                r = self._get_region_rect(current_region)
                pos = r.topLeft().x()
                pen = QPen(delimiter_color)
                hpw = pen.width() / 2
                item = QGraphicsLineItem(pos,
                                         hpw,
                                         pos,
                                         self._height - hpw,
                                         parent=self)
                item.setPen(pen)
                item.setZValue(self.ZVALUE_SEPARATOR)
                self._map_items.append(item)

            # Clip item to possibly truncated region size
            adjusted_region_size = self._get_adjusted_region_size(
                current_region)
            adjusted_size = min(
                obj.size, current_region.addr + adjusted_region_size - addr)
            if adjusted_size <= 0:
                # Item falls outside truncated region. Drop the item.
                continue

            r = self._get_offset_size_rect(offset, adjusted_size)
            offset += adjusted_size

            if isinstance(obj, MemoryData):
                brush = QBrush(data_color)
            elif isinstance(obj, Block):
                # TODO: Check if it belongs to a function or not
                brush = QBrush(func_color)
            else:
                brush = QBrush(unknown_color)

            item = QGraphicsRectItem(r, parent=self)
            item.setPen(Qt.NoPen)
            item.setBrush(brush)
            self._map_items.append(item)
Пример #18
0
class Connection(SchemeItem):
    """Connection is an input or output from a Node."""
    EdgeDragMimeType = Trigger.DragMimeType

    def __init__(self,
                 text=None,
                 datatype: DataType = None,
                 parent: QGraphicsItem = None):
        super().__init__(parent)

        self.setFlag(
            self.ItemSendsScenePositionChanges)  # To enable edge adjusting
        self.setFlag(self.ItemIsSelectable)
        self.setFlag(
            self.ItemHasNoContents)  # Drawing occurs using child items

        self.edges = set()
        """Edges attached to this connection. To change this set use `Connection`'s methods: attach, detach, detachAll.
        """

        self._text_item = TextLineItem(text or "Connection", self)
        self._stem_item = QGraphicsLineItem(self)

        self._trigger_item = Trigger(self)

        self._datatype = datatype or DataType.Unknown
        self._is_multiple = False
        """Determines if the connection can have multiple edges coming out of it.  
        By default, it is False for Input and True for Output.
        """

        self._approved_selection = True
        """Connection is not selectable from outside sources. This flag is set by some internal methods to indicate that
        a selection is legitimate."""

        self.hideText()
        self.styleChange()
        self.paletteChange()

    # Working with edges ===============================================================================================
    def attach(self, edge):
        """Attach an edge to this connection."""
        raise NotImplementedError

    def detach(self, edge):
        """Detach an edge from this connection.  
        Other connection of this edge is unaffected.
        """
        raise NotImplementedError

    def detachAll(self):
        """Detach all edges."""
        raise NotImplementedError

    # Operations =======================================================================================================
    def showText(self):
        self._text_item.setVisible(True)

    def hideText(self):
        self._text_item.setVisible(False)

    # Member access ====================================================================================================
    def text(self):
        return self._text_item.text()

    def dataType(self):
        return self._datatype

    def isMultiple(self):
        return self._is_multiple

    def setText(self, text):
        self._text_item.setText(text)

    def setDataType(self, datatype):
        self._datatype = datatype

        for edge in self.edges:
            # Verify that all edges are fine with changing the data type.
            edge.checkDataType()

    def setMultiple(self, multiple: bool):
        self._is_multiple = multiple

    # Geometry and drawing =============================================================================================
    def stemRoot(self):
        """Return position of stem's root (where the stem connects to the node) in local inches."""
        raise NotImplementedError

    def stemTip(self):
        """Return position of stem's root (where the stem connects to the edge) in local inches."""
        raise NotImplementedError

    def boundingRect(self):
        return QRectF()

    def paint(self, painter: QPainter, option, widget=...) -> None:
        pass

    # Style and palette ================================================================================================
    def styleChange(self):
        super().styleChange()
        style = self.style()

        self._text_item.setFont(style.font(Style.ConnectionTextFont))
        self._text_item.setMaximumWidth(
            style.pixelMetric(Style.ConnectionTextLength))

        self._stem_item.setPen(style.edgePen(self.palette()))

    def paletteChange(self):
        super().paletteChange()
        text_bg = self.palette().background().color()
        text_bg.setAlpha(196)

        self._text_item.setBackgroundBrush(text_bg)
        self._text_item.setBrush(self.palette().text())

        self._stem_item.setPen(self.style().edgePen(self.palette()))

    # Events ===========================================================================================================
    def itemChange(self, change, value):
        """A function that runs every time some change happens to the connection.
        
        This processes position changes by adjusting all the edges and forwards the arguments to the superclass.
        """
        # ItemScenePositionHasChanged ----------------------------------------------------------------------------------
        if change == self.ItemScenePositionHasChanged or change == self.ItemVisibleHasChanged:
            for edge in self.edges:
                edge.adjust()
        # ItemSelectedChange -------------------------------------------------------------------------------------------
        if change == self.ItemSelectedChange:
            # Connection is not selectable from outside sources. Selection is approved only if the corresponding flag is
            # set (it is set by internal methods).
            if not self._approved_selection:
                value = self.isSelected()
            self._approved_selection = False

        return super().itemChange(change, value)

    def autoSelect(self):
        """This function updates connection selection.
        The connection asks the edges to autoSelect themselves, and they in turn call self.autoSelectFromEdge.
        """
        for edge in self.edges:
            edge.autoSelect()

    def autoSelectFromEdge(self):
        """This function updates connection selection status when an edge changes selection."""
        value = False

        if self.parentItem().isSelected():
            for edge in self.edges:
                if edge.isSelected():
                    value = True
                    break

        if value != self.isSelected():
            self._approved_selection = True
            self.setSelected(value)

    # Serialization ====================================================================================================
    def serialize(self) -> dict:
        return {
            "text": self.text(),
            "datatype": self.dataType(),
            "is_multiple": self.isMultiple(),
        }

    @classmethod
    def deserialize(cls, data: dict):
        obj = cls()
        obj.setText(data["text"])
        obj.setDataType(data["datatype"])
        obj.setMultiple(data["is_multiple"])

        return obj

    # Drawing edges ====================================================================================================
    # The heavy lifting such as detecting when the edge started being drawn, mouse moving and data transfers are handled
    # by a member item called self._trigger_item. Connection handles the logic.
    def edgeDragStart(self):
        """Called when user tries to drag an edge from this connection."""
        if not self.isMultiple():
            self.detachAll()
        self.scene().edgeDragStart(self)

    def edgeDragAccept(self) -> bool:
        """Called when a new edge is being dragged into the drop zone.  
        Returns True or False depending on whether the dragged edge should be accepted or not.
        """
        raise NotImplementedError

    def edgeDragDrop(self):
        """Called when a new edge has been dragged and dropped into this connection's trigger zone.  
        This function is responsible for actually connecting the two nodes with a real edge.
        """
        if not self.isMultiple():
            self.detachAll()

    def edgeDragStop(self):
        """Conclude the edge drawing process.
        This function is called when a drag process from this connection has stopped, regardless of the outcome. (For 
        example, when the edge drawing has failed). Default implementation calls the scene-wide version of this
        function.
        """
        self.scene().edgeDragStop()