Beispiel #1
0
class OIBlock(QWidget):
    border_color = QColor(137, 117, 89)
    padding = 0.05
    radius = 0.08

    def __init__(self, block, parent):
        QWidget.__init__(self, parent)
        self.__nodes = []
        self.__block = block
        self._resizable = True
        self.__block.repaint.connect(self.repaint)
        self._bg_color = QColor(159, 160, 144, 255)
        self._fg_color = QColor(255, 255, 255)
        self.setGeometry(block.get_geometry(Info.dpi))
        self.__action = Action.NONE
        self.__status = Mode.EDIT_LOGIC
        self.__corner_path = None
        self.__origin = None
        self.__translation = QPoint()
        if self._resizable:
            self.__init_corner()
        self.__init_nodes()
        self.__init_listeners()
        self.setMouseTracking(True)

    def __init_nodes(self):
        y = .45
        x = .01
        for k in self.__block.inputs:
            i = self.__block.inputs[k]
            n = OINode(QPointF(x, y), Alignment.Left, i)
            self.__nodes.append(n)
            y += 0.05 + n.size
        x = self.width() / Info.dpi - .12
        y = 0.45
        for k in self.__block.outputs:
            o = self.__block.outputs[k]
            n = OINode(QPointF(x, y), Alignment.Right, o)
            self.__nodes.append(n)
            y += .05 + n.size

    def __init_listeners(self):
        self.__block.selected.connect(self.select)
        self.__block.settings['Width'].value_update.connect(
            self.geometry_update)
        self.__block.settings['Height'].value_update.connect(
            self.geometry_update)
        self.__block.settings['X'].value_update.connect(self.geometry_update)
        self.__block.settings['Y'].value_update.connect(self.geometry_update)

    def select(self, val: bool):
        if val:
            effect = QGraphicsDropShadowEffect()
            effect.setBlurRadius(20)
            effect.setXOffset(0)
            effect.setYOffset(0)
            effect.setColor(QColor(0, 0, 0, 180))
            self.setGraphicsEffect(effect)
            self.raise_()
        else:
            eff = self.graphicsEffect()
            del eff
            self.setGraphicsEffect(None)

    def geometry_update(self):
        r = self.__block.get_geometry(Info.dpi)
        r.translate(self.__translation)
        self.setGeometry(r)
        self.__update_nodes()

    def __update_nodes(self):
        x = self.width() / Info.dpi - .12
        for n in self.__nodes:
            if n.alignment == Alignment.Right:
                y = n.pos.y()
                n.pos = QPointF(x, y)
        self.repaint()

    def selected(self):
        return self.__block.is_selected()

    def bg(self):
        return self._bg_color

    def title_bg(self):
        return self._bg_color.light(80)

    def block(self):
        return self.__block

    def _paint(self, p: QPainter):
        self._paint_bg(p)
        self._paint_title(p)
        p.setPen(QPen(self.pen().brush(), 0.01 * Info.dpi))
        self._paint_nodes(p)
        # self._paint_outs(p)
        # self._paint_content(p)

    def pen(self):
        p = QPen(
            OIBlock.border_color.lighter().lighter()
            if self.selected() else OIBlock.border_color, .02 * Info.dpi)
        return p

    def _paint_bg(self, p: QPainter):
        dpi = Info.dpi
        pen = self.pen()
        p.setRenderHint(QPainter.Antialiasing, True)
        p.setPen(pen)
        p.setBrush(self.bg())
        p.drawRoundedRect(OIBlock.padding * dpi, OIBlock.padding * dpi,
                          self.width() - 2 * OIBlock.padding * dpi,
                          self.height() - 2 * OIBlock.padding * dpi,
                          OIBlock.radius * dpi, OIBlock.radius * dpi)
        p.setBrush(self.title_bg())
        p.drawRoundedRect(OIBlock.padding * dpi, OIBlock.padding * dpi,
                          self.width() - 2 * OIBlock.padding * dpi,
                          .35 * dpi + OIBlock.padding * dpi,
                          OIBlock.radius * dpi, OIBlock.radius * dpi)
        p.setBrush(self.bg())
        p.setPen(QColor(0, 0, 0, 0))
        p.drawRect(0.01 * dpi + OIBlock.padding * dpi,
                   0.35 * dpi + OIBlock.padding * dpi,
                   self.width() - 0.02 * dpi - 2 * OIBlock.padding * dpi,
                   0.10 * dpi)
        p.setPen(pen)
        if self._resizable:
            if self.__corner_path is None:
                self.__init_corner()
            p.setBrush(pen.brush())
            p.drawPath(
                self.__corner_path.translated(self.width(), self.height()))

    def _paint_title(self, p: QPainter):
        dpi = Info.dpi
        p.drawLine(OIBlock.padding * dpi, 0.35 * dpi + OIBlock.padding * dpi,
                   self.width() - (0.01 + OIBlock.padding) * dpi,
                   0.35 * dpi + OIBlock.padding * dpi)
        p.setPen(self._fg_color)
        f = p.font()
        f.setPointSize(10)
        f.setBold(True)
        p.setFont(f)
        p.drawText(
            QRectF((0.04 + OIBlock.padding) * dpi,
                   (OIBlock.padding + .01) * dpi,
                   self.width() - .12 * dpi, .25 * dpi),
            str(self.__block.name()))
        f.setBold(False)
        f.setPointSize(8)
        p.setPen(
            QColor(self._fg_color.red(), self._fg_color.green(),
                   self._fg_color.blue(), 100))
        p.setFont(f)
        p.drawText(
            QRectF((.04 + OIBlock.padding) * dpi,
                   (.17 + OIBlock.padding) * dpi,
                   self.width() - .12 * dpi, .15 * dpi),
            str(self.__block.type_name()))

    def __init_corner(self):
        path = QPainterPath()
        dpi = Info.dpi
        path.moveTo(-OIBlock.padding * 1.2 * dpi,
                    (-.15 - OIBlock.padding * 1.2) * dpi)
        path.lineTo((-.15 - OIBlock.padding * 1.2) * dpi,
                    -OIBlock.padding * 1.2 * dpi)
        path.lineTo(-OIBlock.padding * 1.2 * dpi, -OIBlock.padding * 1.2 * dpi)
        path.closeSubpath()
        self.__corner_path = path

    def _paint_nodes(self, p: QPainter):
        for n in self.__nodes:
            n.paint(p)
        return

    def _paint_content(self, p: QPainter):
        # nothing to do
        return

    def paintEvent(self, e: QPaintEvent):
        if e.isAccepted():
            p = QPainter(self)
            self._paint(p)

    def _check_corner(self, pos):
        path = self.__corner_path.translated(self.width(), self.height())
        return path.contains(pos)

    def _check_action(self, action):
        if self.__action != Action.NONE and action != Action.NONE:
            return False
        return True

    def _check_nodes(self, p: QPoint):
        for n in self.__nodes:
            if n.contains(p):
                return n
        return None

    def mousePressEvent(self, e: QMouseEvent):
        self.__block.select()
        n = self._check_nodes(e.pos())
        if n is not None:
            print('Node found')
            return
        if e.button() == Qt.LeftButton:
            if self._resizable:
                if self._check_corner(e.pos()) and self._check_action(
                        Action.RESIZE):
                    self.__origin = e.pos()
                    self.__action = Action.RESIZE
                    self.setCursor(Qt.SizeFDiagCursor)
                    return
            if self._check_action(Action.DRAG):
                self.__origin = e.pos()
                self.__action = Action.DRAG
                self.setCursor(Qt.DragMoveCursor)

    def mouseMoveEvent(self, e: QMouseEvent):
        if self.__action == Action.DRAG:
            dx = e.x() - self.__origin.x()
            dy = e.y() - self.__origin.y()
            self.set_pos(self.x() + dx, self.y() + dy)
        elif self.__action == Action.RESIZE:
            self.set_size(e.x(), e.y())
        else:
            if self._resizable and self.__corner_path.translated(
                    self.width(), self.height()).contains(e.pos()):
                self.setCursor(Qt.SizeFDiagCursor)
            else:
                self.setCursor(Qt.ArrowCursor)

    def mouseReleaseEvent(self, e: QMouseEvent):
        self.__action = Action.NONE
        self.setCursor(Qt.ArrowCursor)

    def set_size(self, w, h):
        w1 = w / Info.dpi
        h1 = h / Info.dpi
        W = self.__block.settings['Width'].value()
        H = self.__block.settings['Height'].value()
        if w1 < W.min:
            w1 = W.min
        elif w1 > W.max:
            w1 = W.max
        if h1 < H.min:
            h1 = H.min
        elif h1 > H.max:
            h1 = H.max

        self.__block.set_setting('Width', w1)
        self.__block.set_setting('Height', h1)

    def set_pos(self, x, y):
        x = x - self.__translation.x()
        y = y - self.__translation.y()
        self.__block.set_setting('X', x / Info.dpi)
        self.__block.set_setting('Y', y / Info.dpi)

    def translate(self, p):
        self.__translation = p
        self.geometry_update()
Beispiel #2
0
    def paint(self, painter, rect, widget_size, draw_highlight):
        if not self.model() or not self.totalValue:
            return
        selections = self.selectionModel()
        option = self.viewOptions()

        background = option.palette.base()
        foreground = QPen(option.palette.color(QPalette.Foreground))

        painter.fillRect(rect, background)
        painter.setPen(foreground)

        if widget_size == self.viewport().rect():
            # We are drawing on screen
            legend_width = LEGEND_WIDTH
            totalSize = self.totalSize
        else:
            # TODO: factorize with resizeEvent
            # We are drawing on printer
            fm = QFontMetrics(painter.font())
            legend_width = fm.width("0000:0000:0000:0000:0000:0000:0000:0000") # Let's use an ipv6 as the legend size reference
            if widget_size.width() - legend_width < widget_size.height():
                totalSize = widget_size.width()
            else:
                totalSize = widget_size.height() + legend_width

            if totalSize < legend_width * 2:
                totalSize = legend_width * 2
            totalSize -= legend_width

        pieSize = totalSize - 2*self.margin

        if self.validItems > 0:
            painter.save()
            painter.drawEllipse(self.margin, self.margin, pieSize, pieSize)

            startAngle = 0.0
            class MyPoint:
                def __init__(self, x = 0, y = 0):
                    self.x = x
                    self.y = y
            def to_rad(x):
                return x / 180.0 * M_PI

            pies_pos = {}

            keyNumber = 0
            # Draw all parts of pie
            for row in xrange(self.model().rowCount(self.rootIndex())):

                index = self.model().index(row, 1, self.rootIndex())
                value = self.model().data(index).toDouble()[0]

                if value > 0.0:
                    angle = 360*value/self.totalValue

                    colorIndex = self.model().index(row, 0, self.rootIndex())
                    color = QColor(self.model().data(colorIndex, Qt.DecorationRole).toString())

                    if self.highlight and index.row() == self.highlight.row():
                        color = color.light(120)

                    # Create the gradient effect
                    grad = QRadialGradient(0.0, 0.0, pieSize / 2.0 + 10.0)
                    grad.setColorAt(1.0, Qt.black)
                    grad.setColorAt(0.85, color)
                    grad.setColorAt(0.0, color)

                    painter.setBrush(QBrush(grad))
                    painter.setBrushOrigin(totalSize / 2, totalSize / 2)

                    painter.drawPie(self.margin, self.margin, pieSize, pieSize, int(startAngle*16), int(angle*16))
                    point_angle = (startAngle + (angle / 2.0))
                    pies_pos[keyNumber] = MyPoint(self.margin + (pieSize / 2.0) * (1.0 + 0.66 * cos(to_rad(point_angle))),
                                                  self.margin + (pieSize / 2.0) * (1.0 - 0.66 * sin(to_rad(point_angle))))

                    startAngle += angle
                    keyNumber += 1

            # Todo: factorize-me
            if draw_highlight:
                keyNumber = 0
                for row in xrange(self.model().rowCount(self.rootIndex())):
                    index = self.model().index(row, 1, self.rootIndex())
                    value = self.model().data(index).toDouble()[0]

                    if keyNumber >= len(pies_pos):
                        break

                    if value > 0.0:
                        if self.highlight and index.row() == self.highlight.row():
                            itemHeight = QFontMetrics(painter.font()).height()

                            x0 = pies_pos[keyNumber].x
                            y0 = pies_pos[keyNumber].y

                            x2 = totalSize + itemHeight
                            y2 = self.margin + (keyNumber +0.5) * itemHeight

                            y1 = y2
                            if y0 > y1:
                                x1 = x0 + (y0 - y1) / 2
                            else:
                                x1 = x0 + (y1 - y0) / 2

                            painter.drawLine(x0, y0, x1, y1)
                            painter.drawLine(x1, y1, x2, y2)
                        keyNumber += 1

            # Draw the legend
            keyNumber = 0
            for row in xrange(self.model().rowCount(self.rootIndex())):

                index = self.model().index(row, 1, self.rootIndex())
                value = self.model().data(index).toDouble()[0]

                if value > 0.0:

                    labelIndex = self.model().index(row, 0, self.rootIndex())
                    color = QColor(labelIndex.data(Qt.DecorationRole).toString())
                    txt = unicode(labelIndex.data().toString())

                    painter.setBrush(color)
                    itemHeight = QFontMetrics(painter.font()).height()
                    x = totalSize + itemHeight
                    y = self.margin + keyNumber * itemHeight
                    painter.drawRect(x, y, itemHeight, itemHeight)
                    painter.drawText(QRect(x + 1.5 * itemHeight, y, legend_width - 2 * itemHeight, itemHeight), Qt.AlignLeft|Qt.AlignVCenter, txt)

                    keyNumber += 1

            painter.restore()
Beispiel #3
0
class OIBlock(QWidget):
    border_color = QColor(137, 117, 89)
    padding = 0.05
    radius = 0.08

    def __init__(self, block, parent):
        QWidget.__init__(self, parent)
        self.__nodes = []
        self.__block = block
        self._resizable = True
        self.__block.repaint.connect(self.repaint)
        self._bg_color = QColor(159, 160, 144, 255)
        self._fg_color = QColor(255, 255, 255)
        self.setGeometry(block.get_geometry(Info.dpi))
        self.__action = Action.NONE
        self.__status = Mode.EDIT_LOGIC
        self.__corner_path = None
        self.__origin = None
        self.__translation = QPoint()
        if self._resizable:
            self.__init_corner()
        self.__init_nodes()
        self.__init_listeners()
        self.setMouseTracking(True)

    def __init_nodes(self):
        y = .45
        x = .01
        for k in self.__block.inputs:
            i = self.__block.inputs[k]
            n = OINode(QPointF(x, y), Alignment.Left, i)
            self.__nodes.append(n)
            y += 0.05 + n.size
        x = self.width() / Info.dpi - .12
        y = 0.45
        for k in self.__block.outputs:
            o = self.__block.outputs[k]
            n = OINode(QPointF(x, y), Alignment.Right, o)
            self.__nodes.append(n)
            y += .05 + n.size

    def __init_listeners(self):
        self.__block.selected.connect(self.select)
        self.__block.settings['Width'].value_update.connect(self.geometry_update)
        self.__block.settings['Height'].value_update.connect(self.geometry_update)
        self.__block.settings['X'].value_update.connect(self.geometry_update)
        self.__block.settings['Y'].value_update.connect(self.geometry_update)

    def select(self, val: bool):
        if val:
            effect = QGraphicsDropShadowEffect()
            effect.setBlurRadius(20)
            effect.setXOffset(0)
            effect.setYOffset(0)
            effect.setColor(QColor(0, 0, 0, 180))
            self.setGraphicsEffect(effect)
            self.raise_()
        else:
            eff = self.graphicsEffect()
            del eff
            self.setGraphicsEffect(None)

    def geometry_update(self):
        r = self.__block.get_geometry(Info.dpi)
        r.translate(self.__translation)
        self.setGeometry(r)
        self.__update_nodes()

    def __update_nodes(self):
        x = self.width() / Info.dpi - .12
        for n in self.__nodes:
            if n.alignment == Alignment.Right:
                y = n.pos.y()
                n.pos = QPointF(x, y)
        self.repaint()

    def selected(self):
        return self.__block.is_selected()

    def bg(self):
        return self._bg_color

    def title_bg(self):
        return self._bg_color.light(80)

    def block(self):
        return self.__block

    def _paint(self, p: QPainter):
        self._paint_bg(p)
        self._paint_title(p)
        p.setPen(QPen(self.pen().brush(), 0.01 * Info.dpi))
        self._paint_nodes(p)
        # self._paint_outs(p)
        # self._paint_content(p)

    def pen(self):
        p = QPen(OIBlock.border_color.lighter().lighter() if self.selected() else OIBlock.border_color, .02 * Info.dpi)
        return p

    def _paint_bg(self, p: QPainter):
        dpi = Info.dpi
        pen = self.pen()
        p.setRenderHint(QPainter.Antialiasing, True)
        p.setPen(pen)
        p.setBrush(self.bg())
        p.drawRoundedRect(OIBlock.padding * dpi, OIBlock.padding * dpi, self.width() - 2 * OIBlock.padding * dpi,
                          self.height() - 2 * OIBlock.padding * dpi, OIBlock.radius * dpi, OIBlock.radius * dpi)
        p.setBrush(self.title_bg())
        p.drawRoundedRect(OIBlock.padding * dpi, OIBlock.padding * dpi, self.width() - 2 * OIBlock.padding * dpi,
                          .35 * dpi + OIBlock.padding * dpi, OIBlock.radius * dpi,
                          OIBlock.radius * dpi)
        p.setBrush(self.bg())
        p.setPen(QColor(0, 0, 0, 0))
        p.drawRect(0.01 * dpi + OIBlock.padding * dpi, 0.35 * dpi + OIBlock.padding * dpi,
                   self.width() - 0.02 * dpi - 2 * OIBlock.padding * dpi, 0.10 * dpi)
        p.setPen(pen)
        if self._resizable:
            if self.__corner_path is None:
                self.__init_corner()
            p.setBrush(pen.brush())
            p.drawPath(self.__corner_path.translated(self.width(), self.height()))

    def _paint_title(self, p: QPainter):
        dpi = Info.dpi
        p.drawLine(OIBlock.padding * dpi, 0.35 * dpi + OIBlock.padding * dpi,
                   self.width() - (0.01 + OIBlock.padding) * dpi,
                   0.35 * dpi + OIBlock.padding * dpi)
        p.setPen(self._fg_color)
        f = p.font()
        f.setPointSize(10)
        f.setBold(True)
        p.setFont(f)
        p.drawText(
            QRectF((0.04 + OIBlock.padding) * dpi, (OIBlock.padding + .01) * dpi, self.width() - .12 * dpi, .25 * dpi),
            str(self.__block.name()))
        f.setBold(False)
        f.setPointSize(8)
        p.setPen(QColor(self._fg_color.red(), self._fg_color.green(), self._fg_color.blue(), 100))
        p.setFont(f)
        p.drawText(
            QRectF((.04 + OIBlock.padding) * dpi, (.17 + OIBlock.padding) * dpi, self.width() - .12 * dpi, .15 * dpi),
            str(self.__block.type_name()))

    def __init_corner(self):
        path = QPainterPath()
        dpi = Info.dpi
        path.moveTo(-OIBlock.padding * 1.2 * dpi, (-.15 - OIBlock.padding * 1.2) * dpi)
        path.lineTo((-.15 - OIBlock.padding * 1.2) * dpi, -OIBlock.padding * 1.2 * dpi)
        path.lineTo(-OIBlock.padding * 1.2 * dpi, -OIBlock.padding * 1.2 * dpi)
        path.closeSubpath()
        self.__corner_path = path

    def _paint_nodes(self, p: QPainter):
        for n in self.__nodes:
            n.paint(p)
        return

    def _paint_content(self, p: QPainter):
        # nothing to do
        return

    def paintEvent(self, e: QPaintEvent):
        if e.isAccepted():
            p = QPainter(self)
            self._paint(p)

    def _check_corner(self, pos):
        path = self.__corner_path.translated(self.width(), self.height())
        return path.contains(pos)

    def _check_action(self, action):
        if self.__action != Action.NONE and action != Action.NONE:
            return False
        return True

    def _check_nodes(self, p:QPoint):
        for n in self.__nodes:
            if n.contains(p):
                return n
        return None

    def mousePressEvent(self, e: QMouseEvent):
        self.__block.select()
        n = self._check_nodes(e.pos())
        if n is not None:
            print('Node found')
            return
        if e.button() == Qt.LeftButton:
            if self._resizable:
                if self._check_corner(e.pos()) and self._check_action(Action.RESIZE):
                    self.__origin = e.pos()
                    self.__action = Action.RESIZE
                    self.setCursor(Qt.SizeFDiagCursor)
                    return
            if self._check_action(Action.DRAG):
                self.__origin = e.pos()
                self.__action = Action.DRAG
                self.setCursor(Qt.DragMoveCursor)

    def mouseMoveEvent(self, e: QMouseEvent):
        if self.__action == Action.DRAG:
            dx = e.x() - self.__origin.x()
            dy = e.y() - self.__origin.y()
            self.set_pos(self.x() + dx, self.y() + dy)
        elif self.__action == Action.RESIZE:
            self.set_size(e.x(), e.y())
        else:
            if self._resizable and self.__corner_path.translated(self.width(), self.height()).contains(e.pos()):
                self.setCursor(Qt.SizeFDiagCursor)
            else:
                self.setCursor(Qt.ArrowCursor)

    def mouseReleaseEvent(self, e: QMouseEvent):
        self.__action = Action.NONE
        self.setCursor(Qt.ArrowCursor)

    def set_size(self, w, h):
        w1 = w / Info.dpi
        h1 = h / Info.dpi
        W = self.__block.settings['Width'].value()
        H = self.__block.settings['Height'].value()
        if w1 < W.min:
            w1 = W.min
        elif w1 > W.max:
            w1 = W.max
        if h1 < H.min:
            h1 = H.min
        elif h1 > H.max:
            h1 = H.max

        self.__block.set_setting('Width', w1)
        self.__block.set_setting('Height', h1)

    def set_pos(self, x, y):
        x = x - self.__translation.x()
        y = y - self.__translation.y()
        self.__block.set_setting('X', x / Info.dpi)
        self.__block.set_setting('Y', y / Info.dpi)

    def translate(self, p):
        self.__translation = p
        self.geometry_update()