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

        measure_pen = QPen(QColor(0, 0, 0, 120), 3)
        half_measure_pen = QPen(QColor(0, 0, 0, 40), 2)
        line_pen = QPen(QColor(0, 0, 0, 40))
        for i in range(0, int(self.num_measures) + 1):
            measure = QGraphicsLineItem(
                0, 0, 0,
                self.piano_height + self.header_height - measure_pen.width(),
                self.header)
            measure.setPos(self.measure_width * i, 0.5 * measure_pen.width())
            measure.setPen(measure_pen)
            if i < self.num_measures:
                number = QGraphicsSimpleTextItem('%d' % (i + 1), self.header)
                number.setPos(self.measure_width * i + 5, 2)
                number.setBrush(Qt.white)
                for j in self.frange(
                        0, self.time_sig[0] * self.grid_div / self.time_sig[1],
                        1.):
                    line = QGraphicsLineItem(0, 0, 0, self.piano_height,
                                             self.header)
                    line.setZValue(1.0)
                    line.setPos(self.measure_width * i + self.value_width * j,
                                self.header_height)
                    if j == self.time_sig[0] * self.grid_div / self.time_sig[
                            1] / 2.0:
                        line.setPen(half_measure_pen)
                    else:
                        line.setPen(line_pen)
Esempio n. 2
0
    def drawGrid(self):
        black_notes = [2,4,6,9,11]
        scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano)
        scale_bar.setPos(self.piano_width, 0)
        scale_bar.setBrush(QColor(100,100,100))
        clearpen = QPen(QColor(0,0,0,0))
        for i in range(self.end_octave - self.start_octave, self.start_octave - self.start_octave, -1):
            for j in range(self.notes_in_octave, 0, -1):
                scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano)
                scale_bar.setPos(self.piano_width, self.note_height * j + self.octave_height * (i - 1))
                scale_bar.setPen(clearpen)
                if j not in black_notes:
                    scale_bar.setBrush(QColor(120,120,120))
                else:
                    scale_bar.setBrush(QColor(100,100,100))

        measure_pen = QPen(QColor(0, 0, 0, 120), 3)
        half_measure_pen = QPen(QColor(0, 0, 0, 40), 2)
        line_pen = QPen(QColor(0, 0, 0, 40))
        for i in range(0, int(self.num_measures) + 1):
            measure = QGraphicsLineItem(0, 0, 0, self.piano_height + self.header_height - measure_pen.width(), self.header)
            measure.setPos(self.measure_width * i, 0.5 * measure_pen.width())
            measure.setPen(measure_pen)
            if i < self.num_measures:
                number = QGraphicsSimpleTextItem('%d' % (i + 1), self.header)
                number.setPos(self.measure_width * i + 5, 2)
                number.setBrush(Qt.white)
                for j in self.frange(0, self.time_sig[0]*self.grid_div/self.time_sig[1], 1.):
                    line = QGraphicsLineItem(0, 0, 0, self.piano_height, self.header)
                    line.setZValue(1.0)
                    line.setPos(self.measure_width * i + self.value_width * j, self.header_height)
                    if j == self.time_sig[0]*self.grid_div/self.time_sig[1] / 2.0:
                        line.setPen(half_measure_pen)
                    else:
                        line.setPen(line_pen)
class CustomGraphicsView(QGraphicsView):
    def __init__(self, parent):
        super().__init__(parent)
        self.pen = QPen(Qt.green, 3, join=Qt.MiterJoin)
        self.item_batch = []
        self.item_batches = collections.deque()

    def wheelEvent(self, event):
        if self.scene() and QApplication.keyboardModifiers(
        ) == Qt.ControlModifier:
            transform = self.transform()
            scale = 1 + ZOOM_FACTOR if event.angleDelta().y(
            ) > 0 else 1 - ZOOM_FACTOR
            self.setTransform(transform * scale)

    def mousePressEvent(self, event):
        if not self.scene():
            return

        position = self.mapToScene(event.x(), event.y())
        item = self.scene().addRect(position.x(),
                                    position.y(), self.pen.width(),
                                    self.pen.width(), self.pen,
                                    self.pen.brush())
        self.item_batch.append(item)

    # TODO: Calculate line between new and last-known position, and draw a rectangle for each point on the line,
    # TODO: addLine() seems to add a different-looking pattern
    def mouseMoveEvent(self, event):
        self.mousePressEvent(event)

    def mouseReleaseEvent(self, event):
        if self.item_batch:
            self.item_batches.append(self.item_batch)
        self.item_batch = []

    # TODO: This is super ugly because we don't use addLine()
    def undo(self):
        if not self.item_batches:
            return

        item_batch = self.item_batches.pop()
        scene = self.scene()
        for item in item_batch:
            scene.removeItem(item)
Esempio n. 4
0
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        roundedRect = QRect()
        radius = 6
        roundedRect.setX(self.rect().x() + radius / 2)
        roundedRect.setY(self.rect().y() + radius / 2)
        roundedRect.setWidth(self.rect().width() - radius)
        roundedRect.setHeight(self.rect().height() - radius)

        palette = QPalette()
        rectColor = palette.color(QPalette.Window)
        painter.setBrush(QBrush(rectColor))
        roundedRectPen = QPen(Qt.black)
        painter.setPen(roundedRectPen)

        painter.drawRoundedRect(roundedRect, radius, radius)

        closeButtonGeometry = self.closeButton.geometry()
        lineColor = palette.color(QPalette.Text)
        pen = QPen(lineColor)
        pen.setWidth(1)
        painter.setPen(pen)
        # horizontal line
        if hasattr(self, 'detailsButton'):
            detailsButtonGeometry = self.detailsButton.geometry()
            y = (closeButtonGeometry.bottom() +
                 detailsButtonGeometry.top()) / 2
            left = QPoint(
                min(closeButtonGeometry.left(), detailsButtonGeometry.left()),
                y)
            right = QPoint(
                max(closeButtonGeometry.right(), detailsButtonGeometry.right())
                - 8, y)
            painter.drawLine(left, right)

        # vertical line
        # close button and details button have Preferred size policy
        x = closeButtonGeometry.left() - pen.width()
        top = QPoint(x, roundedRect.top() + roundedRectPen.width())
        bottom = QPoint(x, roundedRect.bottom() - roundedRectPen.width())
        painter.drawLine(top, bottom)
Esempio n. 5
0
 def line(xml: QXmlStreamWriter, pen: QPen, tag: str = "line"):
     xml.writeStartElement(tag)
     xml.writeAttribute("color", pen.color().name())
     xml.writeAttribute("width", str(pen.width()))
     if pen.style() == Qt.DashLine:
         xml.writeAttribute("style", "dash")
     elif pen.style() == Qt.DotLine:
         xml.writeAttribute("style", "dot")
     else:
         xml.writeAttribute("style", "solid")
     xml.writeEndElement()  #fecha line
Esempio n. 6
0
    def paint(self, painter, option, index):
        background = index.data(Qt.BackgroundRole)
        if isinstance(background, QBrush):
            painter.fillRect(option.rect, background)

        super().paint(painter, option, index)

        if option.state & QStyle.State_Selected:
            painter.save()
            pen = QPen(Qt.black, 2, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin)
            w = pen.width() / 2
            painter.setPen(pen)
            painter.drawRect(option.rect.adjusted(w, w, -w, -w))
            painter.restore()
Esempio n. 7
0
    def setValues(self, pen: QPen):
        for i in range(self.lstPenStyles.count()):
            item = self.lstPenStyles.item(i)
            if item.data(PenParametersDialog.PenStyleRole) == pen.style():
                item.setSelected(True)
                break

        for i in range(self.lstPenColors.count()):
            item = self.lstPenColors.item(i)
            if QColor(item.data(PenParametersDialog.ColorRole)).name(
            ) == pen.color().name():
                item.setSelected(True)
                break

        self.spinPenSize.setValue(pen.width())
Esempio n. 8
0
class AnalogGaugeWidget(QWidget):
    gaugeValueChanged = pyqtSignal(int)

    def __init__(self, parent=None):
        super(AnalogGaugeWidget, self).__init__(parent)

        self.useTimerEvent = False

        self.initUI()

    def initUI(self):
        # Color of needle
        self.setNeedleColor(50, 50, 50, 255)

        # Color of needle hub
        self.setNeedleHubColor(50, 50, 50, 255)

        # Color of gauge values
        self.setGaugeValuesColor(255, 255, 255, 255)

        # Color of LCD value
        self.setDigitalValueColor(255, 255, 255, 255)

        # Gauge needle object
        self.needle = QObject
        self.setNeedleStyle([
            QPolygon([
                QPoint(4, 4),
                QPoint(-4, 4),
                QPoint(-3, -120),
                QPoint(0, -126),
                QPoint(3, -120)
            ])
        ])

        # minimum gauge value
        self.minGaugeValue = 0

        # maximum gauge value
        self.maxGaugeValue = 500

        # current gauge value
        self.gaugeValue = self.minGaugeValue

        # gauge value units
        self.gaugeValueUnits = ''

        # outer radius of gauge
        self.gaugeOuterRadius = 1

        # inner radius of gauge
        self.gaugeInnerRadius = 0.95

        # orientation of gauge
        self.gaugeRotation = 135

        # number of degrees to draw gauge (360 is a complete circle)
        self.gaugeArcAngle = 270

        # number of gauge values
        self.setGaugeValueMajorAxisCount(10)

        # number of ticks between gauge values
        self.gaugeValueMinorAxisCount = 5

        self.pen = QPen(QColor(0, 0, 0))
        self.font = QFont('Decorative', 20)

        self.gaugeColors = []
        self.setGaugeColors([[.00, Qt.red], [.1, Qt.yellow], [.15, Qt.green],
                             [1, Qt.transparent]])

        # gauge value font family and font size
        self.setGaugeValuesEnabled(True)
        self.gaugeValueFont = "Decorative"
        self.initGaugeValueFontSize = 15
        self.gaugeValueFontSize = self.initGaugeValueFontSize

        # digital value font family and font size
        self.digitalValueEnabled = True
        self.digitalValueFontName = "Decorative"
        self.initDigitalValueFontSize = 40
        self.digitalValueUnitsFontSize = 15
        self.digitalValueFontSize = self.initDigitalValueFontSize
        self.digitalValueRadius = 0.7

        self.setGaugeColorBarsEnabled(True)
        self.setGaugeAnnulusFilledEnabled(True)

        self.needleHubEnabled = True
        self.gaugeMinorAxisMarkerEnabled = True
        self.gaugeMajorAxisMarkerEnabled = True

        self.needleSize = 0.8
        self.needleEnabled = True

        self.update()

        self.resizeGauge()

        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth())
        self.setSizePolicy(sizePolicy)
        self.setMinimumSize(QSize(300, 300))
        self.setMaximumSize(QSize(600, 600))
        self.setBaseSize(QSize(300, 300))

    def resizeGauge(self):
        if self.width() <= self.height():
            self.widgetDiameter = self.width()
        else:
            self.widgetDiameter = self.height()

        self.setNeedleStyle([
            QPolygon([
                QPoint(4, 30),
                QPoint(-4, 30),
                QPoint(-2, -self.widgetDiameter / 2 * self.needleSize),
                QPoint(0, -self.widgetDiameter / 2 * self.needleSize - 6),
                QPoint(2, -self.widgetDiameter / 2 * self.needleSize)
            ])
        ])

        self.gaugeValueFontSize = self.initGaugeValueFontSize * self.widgetDiameter / 400
        self.digitalValueFontSize = self.initDigitalValueFontSize * self.widgetDiameter / 400

    def setNeedleStyle(self, design):
        self.needle = []
        for i in design:
            self.needle.append(i)

        self.update()

    def updateGaugeValue(self, value):
        if value <= self.minGaugeValue:
            self.gaugeValue = self.minGaugeValue
        elif value >= self.maxGaugeValue:
            self.gaugeValue = self.maxGaugeValue
        else:
            self.gaugeValue = value

        self.gaugeValueChanged.emit(int(value))

        self.update()

    ###############################################################################################
    # Set Methods
    ###############################################################################################
    def setNeedleColor(self, R=50, G=50, B=50, Transparency=255):
        self.needleColor = QColor(R, G, B, Transparency)

        self.update()

    def setGaugeValuesColor(self, R=50, G=50, B=50, Transparency=255):
        self.gaugeValuesColor = QColor(R, G, B, Transparency)

        self.update()

    def setDigitalValueColor(self, R=50, G=50, B=50, Transparency=255):
        self.digitalValueColor = QColor(R, G, B, Transparency)

        self.update()

    def setNeedleHubColor(self, R=50, G=50, B=50, Transparency=255):
        self.needleHubColor = QColor(R, G, B, Transparency)

        self.update()

    def setNeedleEnabled(self, enable=True):
        self.needleEnabled = enable

        self.update()

    def setGaugeValuesEnabled(self, enable=True):
        self.gaugeValuesEnabled = enable

        self.update()

    def setGaugeColorBarsEnabled(self, enable=True):
        self.GaugeColorBarsEnabled = enable

        self.update()

    def setDigitalValueEnabled(self, enable=True):
        self.digitalValueEnabled = enable

        self.update()

    def setNeedleHubEnabled(self, enable=True):
        self.needleHubEnabled = enable

        self.update()

    def setGaugeAnnulusFilledEnabled(self, enable=True):
        self.gaugeAnnulusEnabled = enable

        self.update()

    def setGaugeMajorAxisEnabled(self, enable=True):
        self.gaugeMajorAxisMarkerEnabled = enable

        self.update()

    def setGaugeMinorAxisEnabled(self, enable=True):
        self.gaugeMinorAxisMarkerEnabled = enable

        self.update()

    def setGaugeValueMajorAxisCount(self, count):
        if count < 1:
            count = 1

        self.gaugeValueMajorAxisCount = count

        self.update()

    def setGaugeValueUnits(self, unit):
        self.gaugeValueUnits = unit

    def setMinGaugeValue(self, min):
        if self.gaugeValue < min:
            self.gaugeValue = min

        if min >= self.maxGaugeValue:
            self.minGaugeValue = self.maxGaugeValue - 1
        else:
            self.minGaugeValue = min

        self.update()

    def setMaxGaugeValue(self, max):
        if self.gaugeValue > max:
            self.gaugeValue = max

        if max <= self.minGaugeValue:
            self.maxGaugeValue = self.minGaugeValue + 1
        else:
            self.maxGaugeValue = max

        self.update()

    def setGaugeRotation(self, value):
        self.gaugeRotation = value

        self.update()

    def setGaugeArcAngle(self, value):
        self.gaugeArcAngle = value

        self.update()

    def setGaugeOuterRadius(self, value):
        self.gaugeOuterRadius = float(value) / 1000

        self.update()

    def setGaugeInnerRadius(self, value):
        self.gaugeInnerRadius = float(value) / 1000

        self.update()

    def setGaugeColors(self, colorArray):
        if 'list' in str(type(colorArray)):
            self.gaugeColors = colorArray
        elif colorArray == None:
            self.gaugeColors = [[.0, Qt.transparent]]
        else:
            self.gaugeColors = [[.0, Qt.transparent]]

        self.update()

    ###############################################################################################
    # Get Methods
    ###############################################################################################
    def getMaxGaugeValue(self):
        return self.maxGaugeValue

    ###############################################################################################
    # Painter
    ###############################################################################################
    def drawGauge(self, outerRadius, innerRadius, start, length):
        gauge = QPolygonF()

        n = 360  # angle steps size for full circle

        w = 360 / n  # angle per step

        x = 0
        y = 0

        if not self.GaugeColorBarsEnabled:
            length = int(
                round((length / (self.maxGaugeValue - self.minGaugeValue)) *
                      (self.gaugeValue - self.minGaugeValue)))

        # add the points of polygon
        for i in range(length + 1):
            t = w * i + start
            x = outerRadius * math.cos(math.radians(t))
            y = outerRadius * math.sin(math.radians(t))
            gauge.append(QPointF(x, y))

        # create inner circle line from "start + length"-angle to "start"-angle
        for i in range(length + 1):  # add the points of polygon
            t = w * (length - i) + start
            x = innerRadius * math.cos(math.radians(t))
            y = innerRadius * math.sin(math.radians(t))
            gauge.append(QPointF(x, y))

        # close outer line
        gauge.append(QPointF(x, y))
        return gauge

    def drawGaugeAnnulus(self, outlinePenWith=0):
        if not self.gaugeColors == None:
            gaugeAnnulus = QPainter(self)
            gaugeAnnulus.setRenderHint(QPainter.Antialiasing)
            gaugeAnnulus.translate(self.width() / 2, self.height() / 2)

            gaugeAnnulus.setPen(Qt.NoPen)

            self.pen.setWidth(outlinePenWith)
            if outlinePenWith > 0:
                gaugeAnnulus.setPen(self.pen)

            coloredScalePolygon = self.drawGauge(
                ((self.widgetDiameter / 2) -
                 (self.pen.width() / 2)) * self.gaugeOuterRadius,
                (((self.widgetDiameter / 2) -
                  (self.pen.width() / 2)) * self.gaugeInnerRadius),
                self.gaugeRotation, self.gaugeArcAngle)

            gradient = QConicalGradient(
                QPointF(0, 0), -self.gaugeArcAngle - self.gaugeRotation + -1)

            for eachcolor in self.gaugeColors:
                gradient.setColorAt(eachcolor[0], eachcolor[1])

            gaugeAnnulus.setBrush(gradient)
            gaugeAnnulus.drawPolygon(coloredScalePolygon)

    ###############################################################################################
    # Gauge Axis Markers
    ###############################################################################################
    def drawGaugeMajorAxisMarkers(self):
        myPainter = QPainter(self)
        myPainter.setRenderHint(QPainter.Antialiasing)
        myPainter.translate(self.width() / 2, self.height() / 2)

        self.pen = QPen(QColor(0, 0, 0, 255))
        self.pen.setWidth(2)

        myPainter.setPen(self.pen)
        myPainter.rotate(self.gaugeRotation)

        stepsSize = (float(self.gaugeArcAngle) /
                     float(self.gaugeValueMajorAxisCount))
        scaleLineOuterStart = self.widgetDiameter / 2
        scaleLineLength = (self.widgetDiameter / 2) - (self.widgetDiameter /
                                                       20)

        for i in range(self.gaugeValueMajorAxisCount + 1):
            myPainter.drawLine(scaleLineLength, 0, scaleLineOuterStart, 0)
            myPainter.rotate(stepsSize)

    def drawGaugeValues(self):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(self.width() / 2, self.height() / 2)

        font = QFont(self.gaugeValueFont, self.gaugeValueFontSize)
        fm = QFontMetrics(font)

        penShadow = QPen()

        penShadow.setBrush(self.gaugeValuesColor)
        painter.setPen(penShadow)

        gaugeValueRadiusFactor = 0.8
        gaugeValueRadius = self.widgetDiameter / 2 * gaugeValueRadiusFactor

        scalePerDiv = int((self.maxGaugeValue - self.minGaugeValue) /
                          self.gaugeValueMajorAxisCount)

        angleDistance = (float(self.gaugeArcAngle) /
                         float(self.gaugeValueMajorAxisCount))

        for i in range(self.gaugeValueMajorAxisCount + 1):
            text = str(int(self.minGaugeValue + scalePerDiv * i))

            w = fm.width(text) + 1
            h = fm.height()

            painter.setFont(QFont(self.gaugeValueFont,
                                  self.gaugeValueFontSize))
            angle = angleDistance * i + float(self.gaugeRotation)

            x = gaugeValueRadius * math.cos(math.radians(angle))
            y = gaugeValueRadius * math.sin(math.radians(angle))

            text = [
                x - int(w / 2), y - int(h / 2),
                int(w),
                int(h), Qt.AlignCenter, text
            ]

            painter.drawText(text[0], text[1], text[2], text[3], text[4],
                             text[5])

    def drawGaugeMinorAxisMarkers(self):
        myPainter = QPainter(self)
        myPainter.setRenderHint(QPainter.Antialiasing)
        myPainter.translate(self.width() / 2, self.height() / 2)
        myPainter.setPen(Qt.black)
        myPainter.rotate(self.gaugeRotation)

        stepsSize = (float(self.gaugeArcAngle) / float(
            self.gaugeValueMajorAxisCount * self.gaugeValueMinorAxisCount))
        scaleLineOuterStart = self.widgetDiameter / 2
        scaleLineLength = (self.widgetDiameter / 2) - (self.widgetDiameter /
                                                       40)

        for i in range((self.gaugeValueMajorAxisCount *
                        self.gaugeValueMinorAxisCount) + 1):
            myPainter.drawLine(scaleLineLength, 0, scaleLineOuterStart, 0)
            myPainter.rotate(stepsSize)

    def drawDigitalValue(self):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(self.width() / 2, self.height() / 2)

        font = QFont(self.digitalValueFontName, self.digitalValueFontSize)
        fm = QFontMetrics(font)

        penShadow = QPen()
        penShadow.setBrush(self.digitalValueColor)
        painter.setPen(penShadow)

        digitalValueRadius = self.widgetDiameter / 2 * self.digitalValueRadius

        text = str(int(self.gaugeValue))
        w = fm.width(text) + 1
        h = fm.height()
        painter.setFont(
            QFont(self.digitalValueFontName, self.digitalValueFontSize))

        angleEnd = float(self.gaugeRotation + self.gaugeArcAngle - 360)
        angle = (angleEnd - self.gaugeRotation) / 2 + self.gaugeRotation

        x = digitalValueRadius * math.cos(math.radians(angle))
        y = digitalValueRadius * math.sin(math.radians(angle))

        offset = 20 if self.gaugeValueUnits else 0

        text = [
            x - int(w / 2) - offset, y - int(h / 2),
            int(w),
            int(h), Qt.AlignCenter, text
        ]
        painter.drawText(text[0], text[1], text[2], text[3], text[4], text[5])

        self.drawDigitalValueUnits()

    def drawDigitalValueUnits(self):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(self.width() / 2, self.height() / 2)

        font = QFont(self.digitalValueFontName, self.digitalValueUnitsFontSize)
        fm = QFontMetrics(font)

        penShadow = QPen()
        penShadow.setBrush(self.digitalValueColor)
        painter.setPen(penShadow)

        digitalValueRadius = self.widgetDiameter / 2 * self.digitalValueRadius

        text = self.gaugeValueUnits
        w = fm.width(text) + 1
        h = fm.height()
        painter.setFont(
            QFont(self.digitalValueFontName, self.digitalValueUnitsFontSize))

        angleEnd = float(self.gaugeRotation + self.gaugeArcAngle - 360)
        angle = (angleEnd - self.gaugeRotation) / 2 + self.gaugeRotation

        x = digitalValueRadius * math.cos(math.radians(angle))
        y = digitalValueRadius * math.sin(math.radians(angle))

        text = [
            x - int(w / 2) + 20, y - int(h / 2),
            int(w),
            int(h), Qt.AlignCenter, text
        ]
        painter.drawText(text[0], text[1], text[2], text[3], text[4], text[5])

    def drawNeedleHub(self, diameter=30):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        painter.translate(self.width() / 2, self.height() / 2)
        painter.setPen(Qt.NoPen)
        painter.setBrush(self.needleHubColor)

        painter.drawEllipse(int(-diameter / 2), int(-diameter / 2),
                            int(diameter), int(diameter))

    def drawNeedle(self):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        painter.translate(self.width() / 2, self.height() / 2)
        painter.setPen(Qt.NoPen)
        painter.setBrush(self.needleColor)
        painter.rotate((
            (self.gaugeValue - self.minGaugeValue) * self.gaugeArcAngle /
            (self.maxGaugeValue - self.minGaugeValue)) + 90 +
                       self.gaugeRotation)

        painter.drawConvexPolygon(self.needle[0])

    ###############################################################################################
    # Events
    ###############################################################################################
    def resizeEvent(self, event):
        self.resizeGauge()

    def paintEvent(self, event):
        # Main Drawing Event: Executed on every change

        # draw gauge annulus
        if self.gaugeAnnulusEnabled:
            self.drawGaugeAnnulus()

        # draw gauge axis markers
        if self.gaugeMinorAxisMarkerEnabled:
            self.drawGaugeMinorAxisMarkers()
        if self.gaugeMajorAxisMarkerEnabled:
            self.drawGaugeMajorAxisMarkers()

        # draw gauge values
        if self.gaugeValuesEnabled:
            self.drawGaugeValues()

        # display digital value
        if self.digitalValueEnabled:
            self.drawDigitalValue()

        # draw needle
        if self.needleEnabled:
            self.drawNeedle()

        # draw needle hub
        if self.needleHubEnabled:
            self.drawNeedleHub(diameter=(self.widgetDiameter / 6))
Esempio n. 9
0
class ArrowGraphicsItem(QGraphicsItem):
    Type = QGraphicsItem.UserType + 1

    def __init__(self, hero, move, fromSquare, toSquare, squareWidth):
        super(ArrowGraphicsItem, self).__init__()
        self.squareWidth = squareWidth
        self.move = move
        self.fromSquare = fromSquare
        self.toSquare = toSquare
        self.sourcePoint = self.fromSquare.pos() + \
            QPointF(self.squareWidth / 2, self.squareWidth / 2)
        self.destPoint = self.toSquare.pos() + \
            QPointF(self.squareWidth / 2, self.squareWidth / 2)
        self.arrowSize = float(userConfig.config['BOARD']['arrowSize'])
        self.hero = hero
        if self.hero:
            col = QColor(userConfig.config['BOARD']['heroArrowColor'])
        else:
            col = QColor(userConfig.config['BOARD']['enemyArrowColor'])
        self.createPallette(col)

    def type(self):
        return self.Type

    def createPallette(self, col):
        self.brush = QBrush(col)
        self.pen = QPen(self.brush,
                        float(userConfig.config['BOARD']['arrowWidth']),
                        Qt.SolidLine, Qt.RoundCap, Qt.BevelJoin)

    def changeHero(self):
        if self.hero:
            col = QColor(userConfig.config['BOARD']['enemyArrowColor'])
        else:
            col = QColor(userConfig.config['BOARD']['heroArrowColor'])
        self.createPallette(col)
        self.hero = not self.hero

    def adjust(self):
        self.prepareGeometryChange()
        self.sourcePoint = self.fromSquare.pos() + \
            QPointF(self.squareWidth / 2, self.squareWidth / 2)
        self.destPoint = self.toSquare.pos() + \
            QPointF(self.squareWidth / 2, self.squareWidth / 2)

    def boundingRect(self):
        extra = (self.pen.width() + self.arrowSize) / 2.0
        return QRectF(self.sourcePoint,
                      QSizeF(self.destPoint.x() - self.sourcePoint.x(),
                             self.destPoint.y() - self.sourcePoint.y())) \
            .normalized().adjusted(-extra, -extra, extra, extra)

    def paint(self, painter, option, widget):
        assert self.fromSquare is not None
        assert self.toSquare is not None
        line = QLineF(self.sourcePoint, self.destPoint)

        assert(line.length() != 0.0)

        # Draw the arrows if there's enough room.
        angle = math.acos(line.dx() / line.length())
        if line.dy() >= 0:
            angle = (math.pi*2.0) - angle

        destArrowP1 = self.destPoint + QPointF(
                math.sin(angle - math.pi / 3) * self.arrowSize,
                math.cos(angle - math.pi / 3) * self.arrowSize
        )
        destArrowP2 = self.destPoint + QPointF(
                math.sin(angle - math.pi + math.pi / 3) * self.arrowSize,
                math.cos(angle - math.pi + math.pi / 3) * self.arrowSize
        )

        painter.setPen(self.pen)
        painter.setBrush(self.brush)
        # arrowhead1 = QPolygonF([line.p1(), sourceArrowP1, sourceArrowP2])
        arrowhead2 = QPolygonF([line.p2(), destArrowP1, destArrowP2])
        painter.drawPolygon(arrowhead2)

        painter.setPen(self.pen)
        painter.drawLine(line)
Esempio n. 10
0
class TemplateConfigurationScene(QGraphicsScene):
    first_point_added = pyqtSignal()
    second_point_added = pyqtSignal()

    def __init__(self, camera_width: int):
        super().__init__()
        self.upper_left_selected = False
        self.bottom_right_selected = False
        self.line_left = None
        self.line_top = None
        self.line_bot = None
        self.line_right = None
        self.upper_left = None
        self.bottom_right = None
        self.pen = QPen()
        self.pen.setColor(Qt.green)
        self.pen.setWidth(2)

        self.first_mouse_move = True
        self.scale = camera_width / 470

        self.mouse_hori_line = QGraphicsLineItem(0, 0, 0, 0)
        self.mouse_vert_line = QGraphicsLineItem(0, 0, 0, 0)
        self.mouse_hori_line.setPen(self.pen)
        self.mouse_vert_line.setPen(self.pen)

    def _reset(self) -> None:
        self.removeItem(self.line_left)
        self.removeItem(self.line_right)
        self.removeItem(self.line_top)
        self.removeItem(self.line_bot)
        self.upper_left_selected = False
        self.bottom_right_selected = False
        self.first_mouse_move = True

    def _is_mouse_on_scene(self, position) -> None:
        return (position.x() < self.sceneRect().width() - self.pen.width()) \
               and (position.y() < self.sceneRect().height() - self.pen.width())

    def mouseMoveEvent(self, event) -> None:
        if self._is_mouse_on_scene(event.scenePos()):
            self.mouse_hori_line.setLine(
                0,
                event.scenePos().y(),
                self.sceneRect().width() - self.pen.width(),
                event.scenePos().y())
            self.mouse_vert_line.setLine(
                event.scenePos().x(), 0,
                event.scenePos().x(),
                self.sceneRect().height() - self.pen.width())
            if self.first_mouse_move:
                self.first_mouse_move = False
                self.addItem(self.mouse_hori_line)
                self.addItem(self.mouse_vert_line)

    def mousePressEvent(self, event) -> None:
        if self._is_mouse_on_scene(event.scenePos()):
            if not self.upper_left_selected:
                self.upper_left_selected = True
                self.upper_left = event.scenePos() * self.scale
                self.line_top = QGraphicsLineItem(
                    0,
                    event.scenePos().y(),
                    self.sceneRect().width() - self.pen.width(),
                    event.scenePos().y())
                self.line_left = QGraphicsLineItem(
                    event.scenePos().x(), 0,
                    event.scenePos().x(),
                    self.sceneRect().height() - self.pen.width())
                self.line_top.setPen(self.pen)
                self.line_left.setPen(self.pen)
                self.addItem(self.line_top)
                self.addItem(self.line_left)
                self.first_point_added.emit()

            elif not self.bottom_right_selected:
                self.bottom_right_selected = True
                self.bottom_right = event.scenePos() * self.scale
                self.line_bot = QGraphicsLineItem(
                    0,
                    event.scenePos().y(),
                    self.sceneRect().width() - self.pen.width(),
                    event.scenePos().y())
                self.line_right = QGraphicsLineItem(
                    event.scenePos().x(), 0,
                    event.scenePos().x(),
                    self.sceneRect().height() - self.pen.width())
                self.line_bot.setPen(self.pen)
                self.line_right.setPen(self.pen)
                self.addItem(self.line_bot)
                self.addItem(self.line_right)
                self.removeItem(self.mouse_vert_line)
                self.removeItem(self.mouse_hori_line)
                self.second_point_added.emit()
Esempio n. 11
0
class AnalogGaugeWidget(QWidget):
    """Fetches rows from a Bigtable.
    Args:
        none

    """
    valueChanged = pyqtSignal(int)

    def __init__(self, parent=None):
        super(AnalogGaugeWidget, self).__init__(parent)

        self.use_timer_event = False
        self.black = QColor(0, 0, 0, 255)

        # self.valueColor = QColor(50, 50, 50, 255)
        # self.set_valueColor(50, 50, 50, 255)
        # self.NeedleColor = QColor(50, 50, 50, 255)
        self.set_NeedleColor(50, 50, 50, 255)
        self.NeedleColorReleased = self.NeedleColor
        # self.NeedleColorDrag = QColor(255, 0, 00, 255)
        self.set_NeedleColorDrag(255, 0, 00, 255)

        self.set_ScaleValueColor(50, 50, 50, 255)
        self.set_DisplayValueColor(50, 50, 50, 255)

        # self.CenterPointColor = QColor(50, 50, 50, 255)
        self.set_CenterPointColor(50, 50, 50, 255)

        # self.valueColor = black
        # self.black = QColor(0, 0, 0, 255)

        self.value_needle_count = 1
        self.value_needle = QObject
        self.change_value_needle_style([
            QPolygon([
                QPoint(4, 4),
                QPoint(-4, 4),
                QPoint(-3, -120),
                QPoint(0, -126),
                QPoint(3, -120)
            ])
        ])

        self.value_min = 0
        self.value_max = 1000
        self.value = self.value_min
        self.value_offset = 0
        self.value_needle_snapzone = 0.05
        self.last_value = 0

        # self.value2 = 0
        # self.value2Color = QColor(0, 0, 0, 255)

        self.gauge_color_outer_radius_factor = 1
        self.gauge_color_inner_radius_factor = 0.95
        self.center_horizontal_value = 0
        self.center_vertical_value = 0
        self.debug1 = None
        self.debug2 = None
        self.scale_angle_start_value = 135
        self.scale_angle_size = 270
        self.angle_offset = 0

        # self.scala_main_count = 10
        self.set_scala_main_count(10)
        self.scala_subdiv_count = 5

        self.pen = QPen(QColor(0, 0, 0))
        self.font = QFont('Decorative', 20)

        self.scale_polygon_colors = []
        self.set_scale_polygon_colors([[.00, Qt.red], [.1, Qt.yellow],
                                       [.15, Qt.green], [1, Qt.transparent]])

        # initialize Scale value text
        # self.enable_scale_text = True
        self.set_enable_ScaleText(True)
        self.scale_fontname = "Decorative"
        self.initial_scale_fontsize = 15
        self.scale_fontsize = self.initial_scale_fontsize

        # initialize Main value text
        self.enable_value_text = True
        self.value_fontname = "Decorative"
        self.initial_value_fontsize = 40
        self.value_fontsize = self.initial_value_fontsize
        self.text_radius_factor = 0.7

        # En/disable scale / fill
        # self.enable_barGraph = True
        self.set_enable_barGraph(True)
        # self.enable_filled_Polygon = True
        self.set_enable_filled_Polygon(True)

        self.enable_CenterPoint = True
        self.enable_fine_scaled_marker = True
        self.enable_big_scaled_marker = True

        self.needle_scale_factor = 0.8
        self.enable_Needle_Polygon = True

        # necessary for resize
        self.setMouseTracking(False)

        # QTimer sorgt für neu Darstellung alle X ms
        # evtl performance hier verbessern mit self.update() und self.use_timer_event = False
        # todo: self.update als default ohne ueberpruefung, ob self.use_timer_event gesetzt ist oder nicht
        # Timer startet alle 10ms das event paintEvent
        if self.use_timer_event:
            timer = QTimer(self)
            timer.timeout.connect(self.update)
            timer.start(10)
        else:
            self.update()

        self.setWindowTitle("Analog Gauge")

        # self.connect(self, SIGNAL("resize()"), self.rescaleMethod)

        # self.resize(300 , 300)
        self.rescale_method()

    def rescale_method(self):
        # print("slotMethod")
        if self.width() <= self.height():
            self.widget_diameter = self.width()
        else:
            self.widget_diameter = self.height()

        self.change_value_needle_style([
            QPolygon([
                QPoint(4, 30),
                QPoint(-4, 30),
                QPoint(-2,
                       -self.widget_diameter / 2 * self.needle_scale_factor),
                QPoint(
                    0,
                    -self.widget_diameter / 2 * self.needle_scale_factor - 6),
                QPoint(2, -self.widget_diameter / 2 * self.needle_scale_factor)
            ])
        ])
        # needle = [QPolygon([
        #     QPoint(4, 4),
        #     QPoint(-4, 4),
        #     QPoint(-3, -120),
        #     QPoint(0, -126),
        #     QPoint(3, -120)])]
        # print(str(type(needle)).split("'")[1])
        #
        # needle = [2]
        # print(str(type(needle[0])).split("'")[1])

        self.scale_fontsize = self.initial_scale_fontsize * self.widget_diameter / 400
        self.value_fontsize = self.initial_value_fontsize * self.widget_diameter / 400

        # print("slotMethod end")
        pass

    def change_value_needle_style(self, design):
        # prepared for multiple needle instrument
        self.value_needle = []
        for i in design:
            self.value_needle.append(i)
        if not self.use_timer_event:
            self.update()

    def update_value(self, value, mouse_controlled=False):
        # if not mouse_controlled:
        #     self.value = value
        #
        # if mouse_controlled:
        #     self.valueChanged.emit(int(value))

        if value <= self.value_min:
            self.value = self.value_min
        elif value >= self.value_max:
            self.value = self.value_max
        else:
            self.value = value
        # self.paintEvent("")
        self.valueChanged.emit(int(value))
        # print(self.value)

        # ohne timer: aktiviere self.update()
        if not self.use_timer_event:
            self.update()

    def update_angle_offset(self, offset):
        self.angle_offset = offset
        if not self.use_timer_event:
            self.update()

    def center_horizontal(self, value):
        self.center_horizontal_value = value
        # print("horizontal: " + str(self.center_horizontal_value))

    def center_vertical(self, value):
        self.center_vertical_value = value
        # print("vertical: " + str(self.center_vertical_value))

    ###############################################################################################
    # Set Methods
    ###############################################################################################
    def set_NeedleColor(self, R=50, G=50, B=50, Transparency=255):
        # Red: R = 0 - 255
        # Green: G = 0 - 255
        # Blue: B = 0 - 255
        # Transparency = 0 - 255
        self.NeedleColor = QColor(R, G, B, Transparency)
        self.NeedleColorReleased = self.NeedleColor

        if not self.use_timer_event:
            self.update()

    def set_NeedleColorDrag(self, R=50, G=50, B=50, Transparency=255):
        # Red: R = 0 - 255
        # Green: G = 0 - 255
        # Blue: B = 0 - 255
        # Transparency = 0 - 255
        self.NeedleColorDrag = QColor(R, G, B, Transparency)

        if not self.use_timer_event:
            self.update()

    def set_ScaleValueColor(self, R=50, G=50, B=50, Transparency=255):
        # Red: R = 0 - 255
        # Green: G = 0 - 255
        # Blue: B = 0 - 255
        # Transparency = 0 - 255
        self.ScaleValueColor = QColor(R, G, B, Transparency)

        if not self.use_timer_event:
            self.update()

    def set_DisplayValueColor(self, R=50, G=50, B=50, Transparency=255):
        # Red: R = 0 - 255
        # Green: G = 0 - 255
        # Blue: B = 0 - 255
        # Transparency = 0 - 255
        self.DisplayValueColor = QColor(R, G, B, Transparency)

        if not self.use_timer_event:
            self.update()

    def set_CenterPointColor(self, R=50, G=50, B=50, Transparency=255):
        self.CenterPointColor = QColor(R, G, B, Transparency)

        if not self.use_timer_event:
            self.update()

    def set_enable_Needle_Polygon(self, enable=True):
        self.enable_Needle_Polygon = enable

        if not self.use_timer_event:
            self.update()

    def set_enable_ScaleText(self, enable=True):
        self.enable_scale_text = enable

        if not self.use_timer_event:
            self.update()

    def set_enable_barGraph(self, enable=True):
        self.enable_barGraph = enable

        if not self.use_timer_event:
            self.update()

    def set_enable_value_text(self, enable=True):
        self.enable_value_text = enable

        if not self.use_timer_event:
            self.update()

    def set_enable_CenterPoint(self, enable=True):
        self.enable_CenterPoint = enable

        if not self.use_timer_event:
            self.update()

    def set_enable_filled_Polygon(self, enable=True):
        self.enable_filled_Polygon = enable

        if not self.use_timer_event:
            self.update()

    def set_enable_big_scaled_grid(self, enable=True):
        self.enable_big_scaled_marker = enable

        if not self.use_timer_event:
            self.update()

    def set_enable_fine_scaled_marker(self, enable=True):
        self.enable_fine_scaled_marker = enable

        if not self.use_timer_event:
            self.update()

    def set_scala_main_count(self, count):
        if count < 1:
            count = 1
        self.scala_main_count = count

        if not self.use_timer_event:
            self.update()

    def set_MinValue(self, min):
        if self.value < min:
            self.value = min
        if min >= self.value_max:
            self.value_min = self.value_max - 1
        else:
            self.value_min = min

        if not self.use_timer_event:
            self.update()

    def set_MaxValue(self, max):
        if self.value > max:
            self.value = max
        if max <= self.value_min:
            self.value_max = self.value_min + 1
        else:
            self.value_max = max

        if not self.use_timer_event:
            self.update()

    def set_start_scale_angle(self, value):
        # Value range in DEG: 0 - 360
        self.scale_angle_start_value = value
        # print("startFill: " + str(self.scale_angle_start_value))

        if not self.use_timer_event:
            self.update()

    def set_total_scale_angle_size(self, value):
        self.scale_angle_size = value
        # print("stopFill: " + str(self.scale_angle_size))

        if not self.use_timer_event:
            self.update()

    def set_gauge_color_outer_radius_factor(self, value):
        self.gauge_color_outer_radius_factor = float(value) / 1000
        # print(self.gauge_color_outer_radius_factor)

        if not self.use_timer_event:
            self.update()

    def set_gauge_color_inner_radius_factor(self, value):
        self.gauge_color_inner_radius_factor = float(value) / 1000
        # print(self.gauge_color_inner_radius_factor)

        if not self.use_timer_event:
            self.update()

    def set_scale_polygon_colors(self, color_array):
        # print(type(color_array))
        if 'list' in str(type(color_array)):
            self.scale_polygon_colors = color_array
        elif color_array == None:
            self.scale_polygon_colors = [[.0, Qt.transparent]]
        else:
            self.scale_polygon_colors = [[.0, Qt.transparent]]

        if not self.use_timer_event:
            self.update()

    ###############################################################################################
    # Get Methods
    ###############################################################################################

    def get_value_max(self):
        return self.value_max

    ###############################################################################################
    # Painter
    ###############################################################################################

    def create_polygon_pie(self, outer_radius, inner_raduis, start, lenght):
        polygon_pie = QPolygonF()
        # start = self.scale_angle_start_value
        # start = 0
        # lenght = self.scale_angle_size
        # lenght = 180
        # inner_raduis = self.width()/4
        # print(start)
        n = 360  # angle steps size for full circle
        # changing n value will causes drawing issues
        w = 360 / n  # angle per step
        # create outer circle line from "start"-angle to "start + lenght"-angle
        x = 0
        y = 0

        # todo enable/disable bar graf here
        if not self.enable_barGraph:
            # float_value = ((lenght / (self.value_max - self.value_min)) * (self.value - self.value_min))
            lenght = int(
                round((lenght / (self.value_max - self.value_min)) *
                      (self.value - self.value_min)))
            # print("f: %s, l: %s" %(float_value, lenght))
            pass

        # mymax = 0

        for i in range(lenght + 1):  # add the points of polygon
            t = w * i + start - self.angle_offset
            x = outer_radius * math.cos(math.radians(t))
            y = outer_radius * math.sin(math.radians(t))
            polygon_pie.append(QPointF(x, y))
        # create inner circle line from "start + lenght"-angle to "start"-angle
        for i in range(lenght + 1):  # add the points of polygon
            # print("2 " + str(i))
            t = w * (lenght - i) + start - self.angle_offset
            x = inner_raduis * math.cos(math.radians(t))
            y = inner_raduis * math.sin(math.radians(t))
            polygon_pie.append(QPointF(x, y))

        # close outer line
        polygon_pie.append(QPointF(x, y))
        return polygon_pie

    def draw_filled_polygon(self, outline_pen_with=0):
        if not self.scale_polygon_colors == None:
            painter_filled_polygon = QPainter(self)
            painter_filled_polygon.setRenderHint(QPainter.Antialiasing)
            # Koordinatenursprung in die Mitte der Flaeche legen
            painter_filled_polygon.translate(self.width() / 2,
                                             self.height() / 2)

            painter_filled_polygon.setPen(Qt.NoPen)

            self.pen.setWidth(outline_pen_with)
            if outline_pen_with > 0:
                painter_filled_polygon.setPen(self.pen)

            colored_scale_polygon = self.create_polygon_pie(
                ((self.widget_diameter / 2) - (self.pen.width() / 2)) *
                self.gauge_color_outer_radius_factor,
                (((self.widget_diameter / 2) - (self.pen.width() / 2)) *
                 self.gauge_color_inner_radius_factor),
                self.scale_angle_start_value, self.scale_angle_size)

            gauge_rect = QRect(
                QPoint(0, 0),
                QSize(self.widget_diameter / 2 - 1, self.widget_diameter - 1))
            grad = QConicalGradient(
                QPointF(0, 0), -self.scale_angle_size -
                self.scale_angle_start_value + self.angle_offset - 1)

            # todo definition scale color as array here
            for eachcolor in self.scale_polygon_colors:
                grad.setColorAt(eachcolor[0], eachcolor[1])
            # grad.setColorAt(.00, Qt.red)
            # grad.setColorAt(.1, Qt.yellow)
            # grad.setColorAt(.15, Qt.green)
            # grad.setColorAt(1, Qt.transparent)
            painter_filled_polygon.setBrush(grad)
            # self.brush = QBrush(QColor(255, 0, 255, 255))
            # painter_filled_polygon.setBrush(self.brush)
            painter_filled_polygon.drawPolygon(colored_scale_polygon)
            # return painter_filled_polygon

    ###############################################################################################
    # Scale Marker
    ###############################################################################################

    def draw_big_scaled_markter(self):
        my_painter = QPainter(self)
        my_painter.setRenderHint(QPainter.Antialiasing)
        # Koordinatenursprung in die Mitte der Flaeche legen
        my_painter.translate(self.width() / 2, self.height() / 2)

        # my_painter.setPen(Qt.NoPen)
        self.pen = QPen(QColor(0, 0, 0, 255))
        self.pen.setWidth(2)
        # # if outline_pen_with > 0:
        my_painter.setPen(self.pen)

        my_painter.rotate(self.scale_angle_start_value - self.angle_offset)
        steps_size = (float(self.scale_angle_size) /
                      float(self.scala_main_count))
        scale_line_outer_start = self.widget_diameter / 2
        scale_line_lenght = (self.widget_diameter /
                             2) - (self.widget_diameter / 20)
        # print(stepszize)
        for i in range(self.scala_main_count + 1):
            my_painter.drawLine(scale_line_lenght, 0, scale_line_outer_start,
                                0)
            my_painter.rotate(steps_size)

    def create_scale_marker_values_text(self):
        painter = QPainter(self)
        # painter.setRenderHint(QPainter.HighQualityAntialiasing)
        painter.setRenderHint(QPainter.Antialiasing)

        # Koordinatenursprung in die Mitte der Flaeche legen
        painter.translate(self.width() / 2, self.height() / 2)
        # painter.save()
        font = QFont(self.scale_fontname, self.scale_fontsize)
        fm = QFontMetrics(font)

        pen_shadow = QPen()

        pen_shadow.setBrush(self.ScaleValueColor)
        painter.setPen(pen_shadow)

        text_radius_factor = 0.8
        text_radius = self.widget_diameter / 2 * text_radius_factor

        scale_per_div = int(
            (self.value_max - self.value_min) / self.scala_main_count)

        angle_distance = (float(self.scale_angle_size) /
                          float(self.scala_main_count))
        for i in range(self.scala_main_count + 1):
            # text = str(int((self.value_max - self.value_min) / self.scala_main_count * i))
            text = str(int(self.value_min + scale_per_div * i))
            w = fm.width(text) + 1
            h = fm.height()
            painter.setFont(QFont(self.scale_fontname, self.scale_fontsize))
            angle = angle_distance * i + float(self.scale_angle_start_value -
                                               self.angle_offset)
            x = text_radius * math.cos(math.radians(angle))
            y = text_radius * math.sin(math.radians(angle))
            # print(w, h, x, y, text)
            text = [
                x - int(w / 2), y - int(h / 2),
                int(w),
                int(h), Qt.AlignCenter, text
            ]
            painter.drawText(text[0], text[1], text[2], text[3], text[4],
                             text[5])
        # painter.restore()

    def create_fine_scaled_marker(self):
        #  Description_dict = 0
        my_painter = QPainter(self)

        my_painter.setRenderHint(QPainter.Antialiasing)
        # Koordinatenursprung in die Mitte der Flaeche legen
        my_painter.translate(self.width() / 2, self.height() / 2)

        my_painter.setPen(Qt.black)
        my_painter.rotate(self.scale_angle_start_value - self.angle_offset)
        steps_size = (float(self.scale_angle_size) /
                      float(self.scala_main_count * self.scala_subdiv_count))
        scale_line_outer_start = self.widget_diameter / 2
        scale_line_lenght = (self.widget_diameter /
                             2) - (self.widget_diameter / 40)
        for i in range((self.scala_main_count * self.scala_subdiv_count) + 1):
            my_painter.drawLine(scale_line_lenght, 0, scale_line_outer_start,
                                0)
            my_painter.rotate(steps_size)

    def create_values_text(self):
        painter = QPainter(self)
        # painter.setRenderHint(QPainter.HighQualityAntialiasing)
        painter.setRenderHint(QPainter.Antialiasing)

        # Koordinatenursprung in die Mitte der Flaeche legen
        painter.translate(self.width() / 2, self.height() / 2)
        # painter.save()
        # xShadow = 3.0
        # yShadow = 3.0
        font = QFont(self.value_fontname, self.value_fontsize)
        fm = QFontMetrics(font)

        pen_shadow = QPen()

        pen_shadow.setBrush(self.DisplayValueColor)
        painter.setPen(pen_shadow)

        text_radius = self.widget_diameter / 2 * self.text_radius_factor

        # angle_distance = (float(self.scale_angle_size) / float(self.scala_main_count))
        # for i in range(self.scala_main_count + 1):
        text = str(int(self.value))
        w = fm.width(text) + 1
        h = fm.height()
        painter.setFont(QFont(self.value_fontname, self.value_fontsize))

        # Mitte zwischen Skalenstart und Skalenende:
        # Skalenende = Skalenanfang - 360 + Skalenlaenge
        # Skalenmitte = (Skalenende - Skalenanfang) / 2 + Skalenanfang
        angle_end = float(self.scale_angle_start_value +
                          self.scale_angle_size - 360)
        angle = (angle_end - self.scale_angle_start_value
                 ) / 2 + self.scale_angle_start_value

        x = text_radius * math.cos(math.radians(angle))
        y = text_radius * math.sin(math.radians(angle))
        # print(w, h, x, y, text)
        text = [
            x - int(w / 2), y - int(h / 2),
            int(w),
            int(h), Qt.AlignCenter, text
        ]
        painter.drawText(text[0], text[1], text[2], text[3], text[4], text[5])
        # painter.restore()

    def draw_big_needle_center_point(self, diameter=30):
        painter = QPainter(self)
        # painter.setRenderHint(QtGui.QPainter.HighQualityAntialiasing)
        painter.setRenderHint(QPainter.Antialiasing)

        # Koordinatenursprung in die Mitte der Flaeche legen
        painter.translate(self.width() / 2, self.height() / 2)
        painter.setPen(Qt.NoPen)
        # painter.setPen(Qt.NoPen)
        painter.setBrush(self.CenterPointColor)
        # diameter = diameter # self.widget_diameter/6
        painter.drawEllipse(int(-diameter / 2), int(-diameter / 2),
                            int(diameter), int(diameter))

    def draw_needle(self):
        painter = QPainter(self)
        # painter.setRenderHint(QtGui.QPainter.HighQualityAntialiasing)
        painter.setRenderHint(QPainter.Antialiasing)
        # Koordinatenursprung in die Mitte der Flaeche legen
        painter.translate(self.width() / 2, self.height() / 2)
        painter.setPen(Qt.NoPen)
        painter.setBrush(self.NeedleColor)
        painter.rotate(((self.value - self.value_offset - self.value_min) *
                        self.scale_angle_size /
                        (self.value_max - self.value_min)) + 90 +
                       self.scale_angle_start_value)

        painter.drawConvexPolygon(self.value_needle[0])

    ###############################################################################################
    # Events
    ###############################################################################################

    def resizeEvent(self, event):
        # self.resized.emit()
        # return super(self.parent, self).resizeEvent(event)
        # print("resized")
        # print(self.width())
        self.rescale_method()
        # self.emit(QtCore.SIGNAL("resize()"))
        # print("resizeEvent")

    def paintEvent(self, event):
        # Main Drawing Event:
        # Will be executed on every change
        # vgl http://doc.qt.io/qt-4.8/qt-demos-affine-xform-cpp.html
        # print("event", event)

        # colored pie area
        if self.enable_filled_Polygon:
            self.draw_filled_polygon()

        # draw scale marker lines
        if self.enable_fine_scaled_marker:
            self.create_fine_scaled_marker()
        if self.enable_big_scaled_marker:
            self.draw_big_scaled_markter()

        # draw scale marker value text
        if self.enable_scale_text:
            self.create_scale_marker_values_text()

        # Display Value
        if self.enable_value_text:
            self.create_values_text()

        # draw needle 1
        if self.enable_Needle_Polygon:
            self.draw_needle()

        # Draw Center Point
        if self.enable_CenterPoint:
            self.draw_big_needle_center_point(diameter=(self.widget_diameter /
                                                        6))

    ###############################################################################################
    # MouseEvents
    ###############################################################################################

    def setMouseTracking(self, flag):
        def recursive_set(parent):
            for child in parent.findChildren(QObject):
                try:
                    child.setMouseTracking(flag)
                except:
                    pass
                recursive_set(child)

        QWidget.setMouseTracking(self, flag)
        recursive_set(self)

    def mouseReleaseEvent(self, QMouseEvent):
        # print("released")
        self.NeedleColor = self.NeedleColorReleased

        if not self.use_timer_event:
            self.update()
        pass

    def mouseMoveEvent(self, event):
        x, y = event.x() - (self.width() / 2), event.y() - (self.height() / 2)
        if not x == 0:
            angle = math.atan2(y, x) / math.pi * 180
            # winkellaenge der anzeige immer positiv 0 - 360deg
            # min wert + umskalierter wert
            value = (float(math.fmod(angle - self.scale_angle_start_value + 720, 360)) / \
                     (float(self.scale_angle_size) / float(self.value_max - self.value_min))) + self.value_min
            temp = value
            fmod = float(
                math.fmod(angle - self.scale_angle_start_value + 720, 360))
            state = 0
            if (self.value - (self.value_max - self.value_min) * self.value_needle_snapzone) <= \
                    value <= \
                    (self.value + (self.value_max - self.value_min) * self.value_needle_snapzone):
                self.NeedleColor = self.NeedleColorDrag
                # todo: evtl ueberpruefen
                #
                state = 9
                # if value >= self.value_max and self.last_value < (self.value_max - self.value_min) / 2:
                if value >= self.value_max and self.last_value < (
                        self.value_max - self.value_min) / 2:
                    state = 1
                    value = self.value_max
                    self.last_value = self.value_min
                    self.valueChanged.emit(int(value))
                elif value >= self.value_max >= self.last_value:
                    state = 2
                    value = self.value_max
                    self.last_value = self.value_max
                    self.valueChanged.emit(int(value))
                else:
                    state = 3
                    self.last_value = value
                    self.valueChanged.emit(int(value))
Esempio n. 12
0
class GaugeWidget(QWidget):
    def __init__(self, _width=400, _height=400, parent=None):
        super(GaugeWidget, self).__init__(parent)

        self.setWidth(_width)
        self.setHeight(_height)
        self.pen = QPen(QColor(0, 0, 0))
        self.widgetDiameter = 0
        if _width > _height:
            self.widgetDiameter = _width
        else:
            self.widgetDiameter = _height
        self.outerRadiusFactor = 1
        self.innerRadiusFactor = 0.9
        self.scaleAngleStartValue = 165
        self.scaleAngleSize = 210
        self.angleOffset = 0
        self.scalePolygonColors = [[.0, Qt.red], [.33, Qt.yellow],
                                   [.66, Qt.green], [1, Qt.transparent]]
        self.scaleMainCount = 10  # For main ticks
        self.scaleSubDivisionCount = 5  # for inner ticks
        self.scaleValueColor = QColor(50, 50, 50, 255)
        self.needleColor = QColor(50, 50, 50, 255)
        self.centerPointColor = QColor(20, 20, 20, 255)
        self.valueMin = 0
        self.valueMax = 100
        #self.valueFontName = "Decorative"
        self.valueFontName = "Lucida"
        self.valueFontSize = 40
        self.textRadiusFactor = 0.7
        self.displayValueColor = QColor(50, 50, 50, 255)
        self.value = 25  #self.valueMin
        self.valueOffset = 0

        self.scaleFontName = "Decorative"
        self.scaleFontSize = 15
        self.valueNeedle = [
            QPolygon([
                QPoint(4, 4),
                QPoint(-4, 4),
                QPoint(-3, -1 * (self.height() * self.innerRadiusFactor / 2)),
                QPoint(0, -6 - (self.height() * self.innerRadiusFactor / 2)),
                QPoint(3, -1 * (self.height() * self.innerRadiusFactor / 2))
            ])
        ]

    def setWidth(self, _width):
        self.resize(_width, self.height())

    def setHeight(self, _height):
        self.resize(self.width(), _height)

    def paintEvent(self, event):
        self.drawFilledPolygon()
        self.createFineScaledMarker()
        self.drawBigScaledMarker()
        self.createScaleMarkerValuesText()
        self.createValuesText()
        self.drawNeedle()
        self.drawNeedleCenterPoint(diameter=(self.widgetDiameter / 6))

    def createPloygonPie(self, outerRadius, innerRaduis, start, lenght):
        """ Create Polygon for given parameters"""
        polygonPie = QPolygonF()
        n = 360  # angle steps size for full circle
        # changing n value will causes drawing issues
        w = 360 / n  # angle per step
        # create outer circle line from "start"-angle to "start + lenght"-angle
        x = 0
        y = 0

        for i in range(lenght + 1):  # add the points of polygon
            t = w * i + start - self.angleOffset
            x = outerRadius * math.cos(math.radians(t))
            y = outerRadius * math.sin(math.radians(t))
            polygonPie.append(QPointF(x, y))
        # create inner circle line from "start + lenght"-angle to "start"-angle
        for i in range(lenght + 1):  # add the points of polygon
            # print("2 " + str(i))
            t = w * (lenght - i) + start - self.angleOffset
            x = innerRaduis * math.cos(math.radians(t))
            y = innerRaduis * math.sin(math.radians(t))
            polygonPie.append(QPointF(x, y))

        # close outer line
        polygonPie.append(QPointF(x, y))
        return polygonPie

    def drawFilledPolygon(self, outlinePenWidth=0):
        """Fill polygon with gradiant colors, polygon created through createPolygonPie"""
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        # Position in middle of the widget
        painter.translate(self.width() / 2, self.height() / 2)
        painter.setPen(Qt.NoPen)
        self.pen.setWidth(0)
        if outlinePenWidth > 0:
            painter.setPen(self.pen)

        coloredScalePolygon = self.createPloygonPie(
            ((self.widgetDiameter / 2) -
             (self.pen.width() / 2)) * self.outerRadiusFactor,
            (((self.widgetDiameter / 2) -
              (self.pen.width() / 2)) * self.innerRadiusFactor),
            self.scaleAngleStartValue, self.scaleAngleSize)

        grad = QConicalGradient(
            QPointF(0, 0), -self.scaleAngleSize - self.scaleAngleStartValue +
            self.angleOffset - 1)

        # set gradiant colors
        for eachcolor in self.scalePolygonColors:
            grad.setColorAt(eachcolor[0], eachcolor[1])
        painter.setBrush(grad)
        painter.drawPolygon(coloredScalePolygon)

    def createFineScaledMarker(self):
        """Draw fine tick marsk on the color bar"""
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(self.width() / 2, self.height() / 2)
        painter.setPen(Qt.black)
        painter.rotate(self.scaleAngleStartValue - self.angleOffset)
        stepSize = (float(self.scaleAngleSize) /
                    float(self.scaleMainCount * self.scaleSubDivisionCount))
        scaleLineOuterStart = self.widgetDiameter / 2
        #scaleLineLenght = (self.widgetDiameter / 2) - (self.widgetDiameter / 40)
        scaleLineLenght = (self.widgetDiameter / 2) - (
            self.widgetDiameter *
            (self.outerRadiusFactor - self.innerRadiusFactor) / 2)
        for i in range((self.scaleMainCount * self.scaleSubDivisionCount) + 1):
            painter.drawLine(scaleLineLenght, 0, scaleLineOuterStart, 0)
            painter.rotate(stepSize)

    def drawBigScaledMarker(self):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(self.width() / 2, self.height() / 2)
        self.pen = QPen(QColor(0, 0, 0, 255))
        self.pen.setWidth(2)
        painter.setPen(self.pen)
        painter.rotate(self.scaleAngleStartValue - self.angleOffset)
        stepsSize = (float(self.scaleAngleSize) / float(self.scaleMainCount))
        scaleLineOuterStart = self.widgetDiameter / 2
        scaleLineLenght = (self.widgetDiameter / 2) - (self.widgetDiameter /
                                                       20)
        for _ in range(self.scaleMainCount + 1):
            painter.drawLine(scaleLineLenght, 0, scaleLineOuterStart, 0)
            painter.rotate(stepsSize)

    def createScaleMarkerValuesText(self):
        painter = QPainter(self)
        # painter.setRenderHint(QPainter.HighQualityAntialiasing)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(self.width() / 2, self.height() / 2)
        # painter.save()
        font = QFont(self.scaleFontName, self.scaleFontSize)
        fm = QFontMetrics(font)

        penShadow = QPen()

        penShadow.setBrush(self.scaleValueColor)
        painter.setPen(penShadow)

        textRadiusFactor = 0.8
        textRadius = self.widgetDiameter / 2 * textRadiusFactor

        scalePerDiv = int(
            (self.valueMax - self.valueMin) / self.scaleMainCount)

        angleDistance = (float(self.scaleAngleSize) /
                         float(self.scaleMainCount))
        for i in range(self.scaleMainCount + 1):
            # text = str(int((self.valueMax - self.valueMin) / self.scaleMainCount * i))
            text = str(int(self.valueMin + scalePerDiv * i))
            w = fm.width(text) + 1
            h = fm.height()
            painter.setFont(QFont(self.scaleFontName, self.scaleFontSize))
            angle = angleDistance * i + float(self.scaleAngleStartValue -
                                              self.angleOffset)
            x = textRadius * math.cos(math.radians(angle))
            y = textRadius * math.sin(math.radians(angle))
            # print(w, h, x, y, text)
            text = [
                x - int(w / 2), y - int(h / 2),
                int(w),
                int(h), Qt.AlignCenter, text
            ]
            painter.drawText(text[0], text[1], text[2], text[3], text[4],
                             text[5])
        # painter.restore()

    def createValuesText(self):
        painter = QPainter(self)
        # painter.setRenderHint(QPainter.HighQualityAntialiasing)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(self.width() / 2, self.height() / 2)
        font = QFont(self.valueFontName, self.valueFontSize)
        fm = QFontMetrics(font)

        penShadow = QPen()

        penShadow.setBrush(self.displayValueColor)
        painter.setPen(penShadow)

        textRadius = self.widgetDiameter / 2 * self.textRadiusFactor

        # angle_distance = (float(self.scaleAngleSize) / float(self.scala_main_count))
        # for i in range(self.scala_main_count + 1):
        text = str(int(self.value))
        w = fm.width(text) + 1
        h = fm.height()
        painter.setFont(QFont(self.valueFontName, self.valueFontSize))

        angleEnd = float(self.scaleAngleStartValue + self.scaleAngleSize - 360)
        angle = (angleEnd -
                 self.scaleAngleStartValue) / 2 + self.scaleAngleStartValue

        x = textRadius * math.cos(math.radians(angle))
        y = textRadius * math.sin(math.radians(angle))
        text = [
            x - int(w / 2), y - int(h / 2),
            int(w),
            int(h), Qt.AlignCenter, text
        ]
        painter.drawText(text[0], text[1], text[2], text[3], text[4], text[5])

    def drawNeedle(self):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(self.width() / 2, self.height() / 2)
        painter.setPen(Qt.NoPen)
        painter.setBrush(self.needleColor)
        painter.rotate(((self.value - self.valueOffset - self.valueMin) *
                        self.scaleAngleSize /
                        (self.valueMax - self.valueMin)) + 90 +
                       self.scaleAngleStartValue)

        painter.drawConvexPolygon(self.valueNeedle[0])

    def drawNeedleCenterPoint(self, diameter=30):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(self.width() / 2, self.height() / 2)
        painter.setPen(Qt.NoPen)
        painter.setBrush(self.centerPointColor)
        painter.drawEllipse(int(-diameter / 2), int(-diameter / 2),
                            int(diameter), int(diameter))
class RenderArea(QWidget):
    """
    Класс области рисования
    """
    def __init__(self, parent=None):
        super(RenderArea, self).__init__(parent)

        self.sphere = Sphere(self)

        self.pen = QPen(QColor(0, 0, 0), 0)
        self.faces_color = QColor(0, 255, 0)
        self.is_light = False
        self.is_clipping = False

        self.setBackgroundRole(QPalette.Base)
        self.setAutoFillBackground(True)

    def minimumSizeHint(self):
        return QSize(200, 200)

    def sizeHint(self):
        return QSize(400, 400)

    def set_pen_width(self, width):
        self.pen = QPen(self.pen.color(), width)
        self.update()

    def set_pen_color(self, label):
        color = QColorDialog.getColor()
        if color.isValid():
            self.pen = QPen(color, self.pen.width())
            label_palette = QPalette()
            label_palette.setColor(QPalette.WindowText, color)
            label.setPalette(label_palette)
            label.setText("Цвет линии " + color.name())
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setPen(self.pen)

        # Пересчитываем сферу
        self.sphere.recalculate()

        # Рисуем
        for face in self.sphere.geom.faces:
            self.draw_item(face, painter)

        # Окантовка виджета
        painter.setPen(self.palette().dark().color())
        painter.setBrush(Qt.NoBrush)
        painter.drawRect(QRect(0, 0, self.width() - 1, self.height() - 1))

    def draw_item(self, face, painter):
        is_draw = True
        if self.is_clipping:
            is_draw = self.sphere.is_face_visible(face)
        if is_draw:
            polygon = QPolygon()
            for index, point_index in enumerate(face):
                p1_x = int(self.sphere.geom.points[face[index-1]][0])
                p1_y = int(self.sphere.geom.points[face[index-1]][1])
                p1_z = int(self.sphere.geom.points[face[index-1]][2])

                p2_x = int(self.sphere.geom.points[point_index][0])
                p2_y = int(self.sphere.geom.points[point_index][1])
                p2_z = int(self.sphere.geom.points[point_index][2])

                if self.sphere.projection_name == "front":
                    # Фронтальная проекция (вид спереди) -> z = 0
                    real_p1 = QPoint(p1_x, p1_y)
                    real_p2 = QPoint(p2_x, p2_y)
                elif self.sphere.projection_name == "horizontal":
                    # Горизонтальная проекция (вид сверху) -> y = 0
                    real_p1 = QPoint(p1_x, p1_z)
                    real_p2 = QPoint(p2_x, p2_z)
                elif self.sphere.projection_name == "profile":
                    # Профильная проекция (вид сбоку) -> x = 0
                    real_p1 = QPoint(p1_y, p1_z)
                    real_p2 = QPoint(p2_y, p2_z)
                else:
                    real_p1 = QPoint(p1_x, p1_y)
                    real_p2 = QPoint(p2_x, p2_y)

                # Точки для проволочного рисования
                real_p1.setX(self.width()/2 + real_p1.x())
                real_p1.setY(self.height()/2 - real_p1.y())
                real_p2.setX(self.width()/2 + real_p2.x())
                real_p2.setY(self.height()/2 - real_p2.y())

                # Полигоны для рисования с цветом
                polygon.append(real_p1)
                polygon.append(real_p2)

                if not self.is_light:
                    painter.drawLine(real_p1, real_p2)

            if self.is_light:

                painter.setBrush(self.sphere.get_face_light(face, self.faces_color))
                painter.drawPolygon(polygon)

    def set_projection(self, button):
        self.sphere.projection_name = button.objectName()
        self.update()

    def set_clipping(self, state):
        self.is_clipping = True if state == Qt.Checked else False
        self.update()

    def set_faces_color(self, label):
        color = QColorDialog.getColor()
        if color.isValid():
            self.faces_color = color
            label_palette = QPalette()
            label_palette.setColor(QPalette.WindowText, color)
            label.setPalette(label_palette)
            label.setText("Цвет объекта " + color.name())
        self.update()

    def set_light(self, is_light, clipping_checkbox):
        self.is_light = is_light
        clipping_checkbox.setChecked(self.is_light)
        clipping_checkbox.setDisabled(self.is_light)
        self.update()
Esempio n. 14
0
class QImagePainter(QSmoothGraphicsView):

    # signals
    imageFlattened = pyqtSignal(QImage)

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

        self.scene = QGraphicsScene(self)
        self.setScene(self.scene)
        self.setRenderHint(QPainter.Antialiasing)

        self.mainPixmapItem = self.scene.addPixmap(QPixmap())

        self._appContext = None

        # policies
        # self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        # self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.toolbar = QToolBar()
        self.initToolbar()

        self._pen = QPen()
        self._pen.setWidth(50)
        self.setDefaultPenColor()

        self._drawStartPos = None
        self._dynamicOval = None
        self._drawnItems = []

        self.updateDragMode()

    @property
    def appContext(self):
        return self._appContext

    @appContext.setter
    def appContext(self, context):
        self._appContext = context
        self.toolbar.clear()
        self.initToolbar()

    def setMainPixmapFromPath(self, imgPath):

        # set image
        image = QImage(str(imgPath))
        pixmap = self.mainPixmapItem.pixmap()
        pixmap.convertFromImage(image)
        self.setMainPixmap(pixmap)

    def setMainPixmap(self, pixmap):
        self.mainPixmapItem.setPixmap(pixmap)

        # set scene rect
        boundingRect = self.mainPixmapItem.boundingRect()
        margin = 0
        boundingRect += QMarginsF(margin, margin, margin, margin)
        self.scene.setSceneRect(boundingRect)

    def saveImage(self, fileName):
        image = self.flattenImage()
        image.save(fileName)

    def flattenImageIfDrawnOn(self):
        if not len(self._drawnItems) == 0:
            self.flattenImage()

    def flattenImage(self):

        # get region of scene
        area = self.mainPixmapItem.boundingRect()

        # create a QImage to render to and fix up a QPainter for it
        image = QImage(area.width(), area.height(),
                       QImage.Format_ARGB32_Premultiplied)
        painter = QPainter(image)

        # render the region of interest to the QImage
        self.scene.render(painter, QRectF(image.rect()), area)
        painter.end()

        # set this flattened image to this view
        pixmap = self.mainPixmapItem.pixmap()
        pixmap.convertFromImage(image)
        self.setMainPixmap(pixmap)

        # clear the drawings from the view
        self.clearDrawnItems()

        # emit flattened image signal
        self.imageFlattened.emit(image)

        # return the flattened image
        return image

    def clearDrawnItems(self):
        for item in self._drawnItems:
            self.scene.removeItem(item)

        self._drawnItems.clear()

    def removeLastDrawnItem(self):
        try:
            item = self._drawnItems.pop()
        except IndexError:
            pass
        else:
            self.scene.removeItem(item)

    def scaleView(self, scaleFactor):
        # print(f'self.width: {self.width()}')
        # print(f'pixmap.width(): {self.scene.map.mainPixmapItem.boundingRect().width()}')
        self.scale(scaleFactor, scaleFactor)

    def centerImage(self):
        self.centerOn(self.mainPixmapItem)

    def bestFitImage(self):
        self.fitInView(self.mainPixmapItem, Qt.KeepAspectRatio)

    def keyPressEvent(self, event: QKeyEvent):
        key = event.key()
        if key == Qt.Key_Space:
            self.bestFitImage()
        else:
            super().keyPressEvent(event)

    def mousePressEvent(self, event):
        self._drawStartPos = None
        if self.ovalModeAct.isChecked():
            if self.mainPixmapItem.isUnderMouse():
                self._drawStartPos = self.mapToScene(event.pos())
                self._dynamicOval = self.scene.addEllipse(
                    QRectF(self._drawStartPos.x(), self._drawStartPos.y(), 1,
                           1), self._pen)
        else:
            super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if self._dynamicOval:
            pos = self.mapToScene(event.pos())
            self._dynamicOval.setRect(
                QRectF(self._drawStartPos.x(), self._drawStartPos.y(),
                       pos.x() - self._drawStartPos.x(),
                       pos.y() - self._drawStartPos.y()))
        else:
            super().mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        if self._dynamicOval:
            self._drawnItems.append(self._dynamicOval)
            self._dynamicOval = None
        else:
            super().mouseReleaseEvent(event)

    def toggleSelectionMode(self):
        if self.selectionModeAct.isChecked():
            self.ovalModeAct.setChecked(False)
        else:
            self.selectionModeAct.setChecked(True)
        self.updateDragMode()

    def toggleOvalMode(self):
        if self.ovalModeAct.isChecked():
            self.selectionModeAct.setChecked(False)
        else:
            self.ovalModeAct.setChecked(True)
        self.updateDragMode()

    def updateDragMode(self):
        if self.selectionModeAct.isChecked():
            self.setDragMode(QGraphicsView.ScrollHandDrag)
        else:
            self.setDragMode(QGraphicsView.NoDrag)

    @property
    def penWidth(self):
        return self._pen.width()

    @penWidth.setter
    def penWidth(self, value):
        self._pen.setWidth(value)

    @property
    def penColor(self):
        return self._pen.color()

    @penColor.setter
    def penColor(self, value):
        self._pen.setColor(QColor(value))

    def setDefaultPenColor(self):
        self.setPenColor(COLORS['Teleric Blue'])

    def promptForPenWidth(self):
        width, okPressed = QInputDialog.getInt(self, 'Pen Width',
                                               'Pen width (px):',
                                               self.penWidth, 1, 100, 1)
        if okPressed:
            self.penWidth = width

    def setResourcePaths(self):
        if self.appContext is None:
            self.selectionModeFp = './icons/selectIcon.png'
            self.ovalModeFp = './icons/ovalIcon.png'
            self.flattenFp = './icons/saveIcon.png'
            self.undoFp = './icons/undoIcon.png'
            self.penFp = './icons/pen.png'
            self.penWidthFp = './icons/penWidth.png'
        else:
            self.selectionModeFp = self.appContext.get_resource(
                'selectIcon.png')
            self.ovalModeFp = self.appContext.get_resource('ovalIcon.png')
            self.flattenFp = self.appContext.get_resource('saveIcon.png')
            self.undoFp = self.appContext.get_resource('undoIcon.png')
            self.penFp = self.appContext.get_resource('pen.png')
            self.penWidthFp = self.appContext.get_resource('penWidth.png')

    def createActions(self):
        self.setResourcePaths()

        self.selectionModeAct = QAction(QIcon(self.selectionModeFp),
                                        'Select (v)',
                                        self,
                                        checkable=True,
                                        checked=True,
                                        shortcut=Qt.Key_V,
                                        triggered=self.toggleSelectionMode)
        self.ovalModeAct = QAction(QIcon(self.ovalModeFp),
                                   'Draw &Oval (o)',
                                   self,
                                   checkable=True,
                                   checked=False,
                                   shortcut=Qt.Key_O,
                                   triggered=self.toggleOvalMode)
        self.flattenAct = QAction(QIcon(self.flattenFp),
                                  'Save',
                                  self,
                                  shortcut=QKeySequence.Save,
                                  triggered=self.flattenImage)
        self.undoAct = QAction(QIcon(self.undoFp),
                               'Undo',
                               self,
                               shortcut=QKeySequence.Undo,
                               triggered=self.removeLastDrawnItem)

        self.setPenWidthAct = QAction(QIcon(self.penWidthFp),
                                      'Set Pen Width',
                                      self,
                                      triggered=self.promptForPenWidth)

    def addPenToolMenu(self):
        penButton = QToolButton(self)
        penButton.setText('Pen')
        penButton.setIcon(QIcon(self.penFp))
        penButton.setPopupMode(QToolButton.InstantPopup)

        self.penMenu = QMenu(penButton)
        self.penMenu.addAction(self.setPenWidthAct)

        self.addPaletteToMenu(self.penMenu)

        penButton.setMenu(self.penMenu)

        self.toolbar.addWidget(penButton)

    def setPenColor(self, color):
        qColor = QColor(color)
        for a in self.penMenu.actions():
            a.setChecked(False)
            try:
                actionColor = QColor(a.color)
            except AttributeError:
                pass
            else:
                if actionColor == qColor:
                    a.setChecked(True)
                    self.penColor = actionColor

    def addPaletteToMenu(self, menu):
        for name, color in COLORS.items():
            paletteIcon = QPaletteIcon(color)
            action = QAction(paletteIcon, name, self, checkable=True)
            action.color = color
            action.triggered.connect(
                lambda checked, color=color: self.setPenColor(color))
            menu.addAction(action)

    def initToolbar(self):
        self.createActions()
        # self.toolbar.addAction(self.flattenAct)
        self.toolbar.addAction(self.undoAct)
        # self.toolbar.addSeparator()
        self.toolbar.addAction(self.selectionModeAct)
        self.toolbar.addAction(self.ovalModeAct)
        self.addPenToolMenu()
Esempio n. 15
0
class PaintArea(QGraphicsView):

    def __init__(self, width=10, parent=None):
        QGraphicsView.__init__(self, parent)
        self._frame = None
        self._instructions = None
        self.setScene(QGraphicsScene(self))
        self._items = self.scene().createItemGroup([])
        self.setMouseTracking(True)
        self.pen = QPen(Qt.black, width, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        self.painting = False
        self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
        self.viewport().setCursor(self.getCursor())
        self.updateScene()

    def updateScene(self):
        if self._frame:
            self.scene().setBackgroundBrush(Qt.gray)
        oldCanvas = self.canvas()
        self.setSceneRect(QRectF(self.contentsRect()))
        self.centerScene()
        self.scaleItems(oldCanvas, self.canvas())

    def centerScene(self):
        self.centerFrame()
        self.centerInstructions()

    def scaleItems(self, oldCanvas, newCanvas):
        pass

    def canvas(self):
        if self._frame:
            return self._frame.rect()
        return QRectF(self.contentsRect())

    def fitInstructions(self):
        textSize = self._instructions.document().size()
        factor = min(self.canvas().size().width() / textSize.width(),
                     self.canvas().size().height() / textSize.height())
        f = self._instructions.font()
        f.setPointSizeF(f.pointSizeF() * factor)
        self._instructions.setFont(f)

    def centerInstructions(self):
        if self._instructions:
            self.fitInstructions()
            size = self.size()
            textSize = self._instructions.document().size()
            self._instructions.setPos((size.width() - textSize.width()) / 2.0,
                                      (size.height() - textSize.height()) / 2.0)

    def setInstructions(self, text):
        if self._instructions:
            self._instructions.setPlainText(text)
        else:
            self._instructions = self.scene().addText(text, QFont('Arial', 10, QFont.Bold))
            self._instructions.setZValue(-1)
            self._instructions.setDefaultTextColor(QColor(220, 220, 220))
        self._text = text
        self.centerInstructions()

    def setFrame(self, width, height):
        if self._frame:
            self._frame.setRect(0, 0, width, height)
        else:
            self.addFrame(QRectF(0, 0, width, height))
        self.centerScene()

    def addFrame(self, rect):
        self._frame = QGraphicsRectItem(rect)
        self._frame.setPen(QPen(Qt.NoPen))
        self._frame.setBrush(Qt.white)
        self._frame.setZValue(-2)
        self.scene().addItem(self._frame)

    def centerFrame(self):
        if self._frame:
            rect = self._frame.rect()
            size = self.contentsRect()
            factor = min((size.width() + 1) / rect.width(),
                         (size.height() + 1) / rect.height())
            w, h = rect.width() * factor, rect.height() * factor
            self._frame.setRect(size.x() + (size.width() - w) / 2.0,
                                size.y() + (size.height() - h) / 2.0,
                                w, h)

    def resizeEvent(self, event):
        self.updateScene()

    def setBrushSize(self, size):
        self.pen.setWidth(size)
        self.viewport().setCursor(self.getCursor())

    def render(self, painter):
        if self._instructions:
            self.scene().removeItem(self._instructions)
        self.scene().render(painter,
                            source=self.scene().itemsBoundingRect())
        if self._instructions:
            self.scene().addItem(self._instructions)

    def getLines(self):
        items = [item for item in self.scene().items()
                 if item.group() == self._items]
        return self.canvas(), items

    def clear(self):
        for item in self.scene().items():
            if item.group() == self._items:
                self._items.removeFromGroup(item)

    def getCursor(self):
        antialiasing_margin = 1
        size = self.pen.width()
        pixmap = QPixmap(size + antialiasing_margin * 2,
                         size + antialiasing_margin * 2)
        pixmap.fill(Qt.transparent)
        painter = QPainter(pixmap)
        painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
        painter.drawEllipse(QRectF(QPointF(antialiasing_margin, antialiasing_margin),
                                   QSizeF(size, size)))
        painter.end()
        return QCursor(pixmap)

    def addLine(self, start, end):
        if start == end:
            delta = QPointF(.0001, 0)
            end = start - delta
        line = self.scene().addLine(QLineF(start, end), self.pen)
        self._items.addToGroup(line)

    def drawPoint(self, pos):
        delta = QPointF(.0001, 0)
        line = self.scene().addLine(QLineF(pos, pos - delta), self.pen)
        self._items.addToGroup(line)

    def mousePressEvent(self, event):
        self.start = QPointF(self.mapToScene(event.pos()))
        self.painting = True
        self.addLine(self.start, self.start)

    def mouseReleaseEvent(self, event):
        self.painting = False

    def mouseMoveEvent(self, event):
        pos = QPointF(self.mapToScene(event.pos()))
        if self.painting:
            self.addLine(self.start, pos)
            self.start = pos
    def paint(self, painter):
        # use antialiasing
        painter.setRenderHint(QPainter.Antialiasing)

        # connections, connected to layers with the include.phase parameter,
        # have a different opacity than normal connections
        opacity = Constants.itemOpacityInPhase
        if not self.__connection.getNodeEditor().isCurrentPhase(
                self.__connection.getPhase()):
            opacity = Constants.itemOpacityNotInPhase

        # connections between a layer and a in-place working layer have a different color than normal connections
        connectionColor = Constants.connectionItemColor
        if self.__connection.getIsInPlace():
            connectionColor = Constants.itemInPlaceColor

        # set local color object alpha
        connectionColor.setAlpha(opacity)

        # draw highlight if the connection is selected
        if self.__connection.isSelected():
            selectedColor = Constants.selectedColor
            selectedColor.setAlpha(opacity)
            painter.setPen(
                QPen(selectedColor, Constants.connectionItemSelectionSize))
            painter.drawPath(self.__connection.path())

        pen = QPen(connectionColor, Constants.connectionItemSize)

        # if the connection is hidden, draw a dashed line at the start and end of the connection
        if self.__connection.getHidden():
            dashes = []

            # calculate the dashes at the start of the connection
            for i in range(0, Constants.connectionItemHiddenDashCount - 1):
                dashes.append(Constants.connectionItemHiddenDashSize /
                              pen.width())
                dashes.append(Constants.connectionItemHiddenDashSpace /
                              pen.width())
            dashes.append(Constants.connectionItemHiddenDashSize / pen.width())

            # calculate the size of the space between the dashed start and dashed end
            middleSpace = self.__connection.path().length()
            middleSpace -= 2 * Constants.connectionItemHiddenDashCount * Constants.connectionItemHiddenDashSize
            middleSpace -= 2 * (Constants.connectionItemHiddenDashCount -
                                1) * Constants.connectionItemHiddenDashSpace

            dashes.append(middleSpace / pen.width())

            # calculate the dashes at the end of the connection
            for i in range(0, Constants.connectionItemHiddenDashCount):
                dashes.append(Constants.connectionItemHiddenDashSize /
                              pen.width())
                dashes.append(Constants.connectionItemHiddenDashSpace /
                              pen.width())

            pen.setDashPattern(dashes)

        # draw the connection
        painter.setPen(pen)
        painter.drawPath(self.__connection.path())
Esempio n. 17
0
class Arrow(QGraphicsItemGroup):
    def __init__(self, start):
        super().__init__()
        self.fromItem = start
        self.startPoint = None
        self.toItem = None
        self.endPoint = None
        self.setFlag(QGraphicsItem.ItemIsSelectable)
        self.color = Qt.black
        self.pen = QPen(self.color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        self.arrowHead = QPolygonF()

        self.lines = []
        self.qLines = []

        #experimental
        self.setFlag(QGraphicsItem.ItemIsMovable)

    """
	We need to reimplement this function because the arrow is larger 
	than the bounding rectangle of the QGraphicsLineItem. The graphics
	scene uses the bounding rectangle to know which regions of the scene to update
	"""

    def boundingRect(self):
        extra = (self.pen.width() + 20) / 2.0

        #rect = QRectF(self.line().p1(), QSizeF(self.line().p2().x() - self.line().p1().x(),
        #                      self.line().p2().y() - self.line().p1().y()))
        rect = self.calcRect()
        #return self.arrowHead.boundingRect()
        return rect.normalized().adjusted(-extra, -extra, extra, extra)

    """
	The shape function returns a QPainterPath that is the exact shape
	of the item. The QGraphicsLineItem::shape() returns a path with a
	line drawn with the current pen, so we only need to add the arrow
	head. This function is used to check for collisions and selections
	with the mouse.
	"""

    def shape(self):
        #path = super().shape()
        path = QPainterPath()
        #path.addRect(self.calcRect())
        path.addPolygon(self.arrowHead)

        return path

    #redraw, due to moving an object
    def recalcUpdate(self):
        if self.fromItem is None or self.toItem is None:
            return
        coordinates = QLineF(
            self.fromItem.getLinePoint(self.toItem.center())[1],
            self.toItem.getLinePoint(self.fromItem.center())[1])
        #self.setLine(coordinates)

    """
	is called, when one of the items is moved.
	it recalculates the lines
	"""

    def move(self):
        self.startPoint = GeoHelper.movePoint(
            self.posFromItem,
            self.fromItem.getPositionalRect().topLeft(), self.startPoint)
        self.endPoint = GeoHelper.movePoint(
            self.posToItem,
            self.toItem.getPositionalRect().topLeft(), self.endPoint)
        g = Geometry()
        self.lines = g.rectToRect(self.startPoint,
                                  self.fromItem.getPositionalRect(),
                                  self.endPoint,
                                  self.toItem.getPositionalRect())
        self.posToItem = self.toItem.getPositionalRect().topLeft()
        self.posFromItem = self.fromItem.getPositionalRect().topLeft()

        self.update(self.boundingRect())

    def drawLine(self, point, item):
        if item is not None:
            self.setItem2(item, point)
        else:
            self.setPoint2(point)
        self.update(self.boundingRect())
        #trigger paint to update/ redraw
        #self.setLine(self.lines[-1])
        #super().update(self.boundingRect())

    def setPoint2(self, point):
        if self.startPoint is None:
            s1, self.startPoint = self.fromItem.getNearestPoint(point)
        g = Geometry()
        self.lines = g.rectToPoint(self.startPoint,
                                   self.fromItem.getPositionalRect(), point)

    """
	saves second rectangle/Item and end point of a connection

	params
	------
	end: RoundedRect
	     second rectangle/ toItem
	pos: QPointF
	     position of mouse
	"""

    def setItem2(self, end, pos):
        #save endPoint
        s2, self.endPoint = end.getNearestPoint(pos)
        #save endItem
        self.toItem = end
        #save position (for moving)
        self.posToItem = self.toItem.getPositionalRect().topLeft()
        self.posFromItem = self.fromItem.getPositionalRect().topLeft()
        g = Geometry()
        self.lines = g.rectToRect(self.startPoint,
                                  self.fromItem.getPositionalRect(),
                                  self.endPoint, end.getPositionalRect())
        print("a:", self.lines)

    def connect(self, end):
        self.toItem = end
        self.toItem.addInput(self)
        self.fromItem.addOutput(self)

    def calcRect(self):
        minX = self.lines[0].p1().x()
        minY = self.lines[0].p1().y()
        maxX = self.lines[0].p1().x()
        maxY = self.lines[0].p1().y()

        for l in self.lines:
            minX = min(minX, l.p1().x())
            minY = min(minY, l.p1().y())
            maxX = max(maxX, l.p1().x())
            maxY = max(maxY, l.p1().y())
            minX = min(minX, l.p2().x())
            minY = min(minY, l.p2().y())
            maxX = max(maxX, l.p2().x())
            maxY = max(maxY, l.p2().y())

        return QRectF(QPointF(minX, minY), QPointF(maxX, maxY))

    def addOrAppend(self, i, line):
        if len(self.lines) > i:
            self.lines[i] = line
        else:
            self.lines.append(line)

    def resetLines(self, pen):
        for l in self.qLines:
            self.scene().removeItem(l)
        self.qLines = []
        for l in self.lines:
            #line = QGraphicsLineItem(l, self)
            line = LineItem(l, self)
            line.setPen(pen)
            #line.setFlag(QGraphicsItem.ItemIsSelectable)
            self.qLines.append(line)

    def paint(self, painter, option, widget=None):
        arrowSize = 10

        if self.isSelected():
            pen = QPen(Qt.red, 1)
            color = Qt.red
        else:
            pen = self.pen
            color = self.color
        painter.setPen(pen)
        painter.setBrush(color)
        #calculate line
        #coordinates = QLineF(self.fromItem.getLinePoint(self.toItem.center()),
        #	self.toItem.getLinePoint(self.fromItem.center()))
        #self.setLine(coordinates)

        #calculate points of arrow
        line = self.lines[-1]
        angle = math.acos(line.dx() / line.length())
        if line.dy() >= 0:
            angle = (math.pi * 2) - angle

        p1 = line.p2() - QPointF(
            math.sin(angle + math.pi / 3) * arrowSize,
            math.cos(angle + math.pi / 3) * arrowSize)
        p2 = line.p2() - QPointF(
            math.sin(angle + math.pi - math.pi / 3) * arrowSize,
            math.cos(angle + math.pi - math.pi / 3) * arrowSize)

        self.arrowHead.clear()
        self.arrowHead.append(line.p2())
        self.arrowHead.append(p1)
        self.arrowHead.append(p2)
        painter.drawPolygon(self.arrowHead)
        self.resetLines(pen)
Esempio n. 18
0
class PenFormation(InstrumentFormation):
  '''
  Specialize to Qt <QPen>
  
  Redefine:
  - applyTo()
  '''
  
  # TODO: a QPen has a QBrush also, and it needs to be scaled also
  
  def __init__(self, parentSelector, role=""):
    InstrumentFormation.__init__(self, name="Pen", parentSelector=parentSelector, role=role)
    self.instrument = QPen()
    self.styleProperties=[BaseStyleProperty("Color", self.instrument.setColor, self.selector,
                                            default = self.instrument.color(),
                                            resettableValueFactory=ResettableColorValue,
                                            layoutFactory=ColorStylePropertyLayout), 
                          BaseStyleProperty("Width", self.instrument.setWidth, self.selector,
                                           default=self.instrument.width(),
                                           layoutFactory=IntStylePropertyLayout,
                                           minimum=0, maximum=10, singleStep=1),
                          BaseStyleProperty("Style", self.instrument.setStyle, self.selector,
                                            default=self.instrument.style(),
                                            layoutFactory=ComboBoxStylePropertyLayout,
                                            domainModel = config.PenModel)
                          ]


  def applyTo(self, morph):
    '''
    Assert this formation's values have already been applied to instrument via editing (which calls Instrument.setters())
    What remains is to set the instrument to the morph.
    Also, scale instrument correlated with scale of morph.
    '''
    # Callback morph API: only morph knows its scale, and how to inversely scale drawing instrument
    morph.scaleInstrument(self.instrument, baseValue=self.styleProperties[1].resettableValue.value)
    morph.setPen(self.instrument)
    
  """
  def scaledPropagateToInstrument(self, morph):
    '''
    Propagate my values that are transformed,
    after unscaling by the local (item) transform.
    
    Where a DocumentElement has a transform that is used to size it
    (e.g. when the DocumentElement comprises a unit shape, scaled to size.)
    TODO when item transform is 2D and not uniform in x, y???
    
    This is not undoing viewing transform, only local transform.
    
    For a Pen in Qt, width property.
    Note that in Qt, QPen.setWidth() also affects the QPen's QBrush.
    '''
    unscaledWidth = self.styleProperties[1].resettableValue.value()
    itemScale = morph.scale()
    scaledWidthF = 1.0/itemScale * unscaledWidth
    
    # !!! Note float value and setWidthF is float setter
    self.instrument.setWidthF(scaledWidthF)
    #print "PenFormation.applyTo width: item scale, unscaled width, scaled width", itemScale, 
    unscaledWidth, scaledWidthF, " on morph", morph
  """
    
    
Esempio n. 19
0
class Triangle(QGraphicsItem):
    """
        Abstract class knowing how to draw the polygon
    """
    a = 60.0
    h = a * sqrt(3) / 2.0
    p_w = 5

    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent = parent

        self.setFlag(QGraphicsItem.ItemIsSelectable)
        self.setAcceptedMouseButtons(Qt.LeftButton)
        self.pen = QPen(QColor("blue"), self.p_w, Qt.SolidLine, Qt.RoundCap,
                        Qt.RoundJoin)
        self.bg_color = QColor(230, 230, 230, 255)

        self.staple_a = None
        self.staple_b = None
        self.staple_c = None

    def set_staple_by_type(self, type, staple):
        if type is StapleTypeID.A:
            self.staple_a = staple
        if type is StapleTypeID.B:
            self.staple_b = staple
        if type is StapleTypeID.C:
            self.staple_c = staple

    def get_staple_by_type(self, type):
        if type is StapleTypeID.A:
            return self.staple_a
        if type is StapleTypeID.B:
            return self.staple_b
        if type is StapleTypeID.C:
            return self.staple_c

    def has_staple_class_type(self, staple_class_type):
        if type(self.staple_a) is staple_class_type:
            return True
        if type(self.staple_b) is staple_class_type:
            return True
        if type(self.staple_c) is staple_class_type:
            return True
        return False

    def shape(self):
        path = QPainterPath()
        path.addPolygon(self.polygon)
        return path

    def boundingRect(self):
        pen_w = self.pen.width()
        return QRectF(0 - pen_w, 0 - pen_w, self.a + pen_w, self.h + pen_w)

    def load_oligo(self, item, plate_name):
        seq = item["seq"]

        fabric = Staple
        if item["protector"]:
            fabric = Protector

        if item["stype"] == "A":
            self.staple_a = fabric(self,
                                   seq=seq,
                                   type_id=StapleTypeID.A,
                                   plate_name=plate_name,
                                   info=item)
            return self.staple_a

        if item["stype"] is "B":
            self.staple_b = fabric(self,
                                   seq=seq,
                                   type_id=StapleTypeID.B,
                                   plate_name=plate_name,
                                   info=item)
            return self.staple_b

        if item["stype"] is "C":
            self.staple_c = fabric(self,
                                   seq=seq,
                                   type_id=StapleTypeID.C,
                                   plate_name=plate_name,
                                   info=item)
            return self.staple_c

    def paint(self, QPainter, QStyleOptionGraphicsItem, QWidget_widget=None):
        if not self.isEnabled():
            return
        QPainter.setPen(QPen(QColor("white")))
        QPainter.setBrush(QBrush(self.bg_color))
        QPainter.drawPolygon(self.polygon)

        AB = QLineF(self.vertex_A, self.vertex_B)
        BC = QLineF(self.vertex_B, self.vertex_C)
        CA = QLineF(self.vertex_C, self.vertex_A)

        vertices = [self.vertex_A, self.vertex_B, self.vertex_C]

        if self.staple_a:
            self.staple_a.draw(QPainter, vertices)
        if self.staple_b:
            self.staple_b.draw(QPainter, vertices)
        if self.staple_c:
            self.staple_c.draw(QPainter, vertices)

    def __str__(self):
        return "\n".join(
            map(str, [
                "-" * 80, ("L_" if type(self) is TriangleLeft else "R_") +
                str(self.parent.row) + "_" + str(self.parent.col),
                self.staple_a, self.staple_b, self.staple_c, "-" * 80
            ]))

    def random_fill(self, pool):
        for staple in (self.staple_a, self.staple_b, self.staple_c):
            # only works only if no seq assigned
            staple.random_fill(pool)

    def fill_by(self, neighbors, pool):
        mp = {
            StapleTypeID.A: [StapleTypeID.A, StapleTypeID.B],
            StapleTypeID.B: [StapleTypeID.B, StapleTypeID.C],
            StapleTypeID.C: [StapleTypeID.C, StapleTypeID.A],
        }
        nxt = {
            StapleTypeID.A: StapleTypeID.B,
            StapleTypeID.B: StapleTypeID.C,
            StapleTypeID.C: StapleTypeID.A
        }

        for stype, neighbor in zip(StapleTypeID, neighbors):
            strand = self.get_staple_by_type(stype)
            if strand:  #makes sure we do have a strand
                strand_type_1, strand_type_2 = mp[stype]
                neighbor_stand1, neighbor_strand2 = neighbor.get_staple_by_type(strand_type_1), \
                                                    neighbor.get_staple_by_type(strand_type_2)

                self.__strand_staple_neighbor_staple(neighbor_stand1,
                                                     neighbor_strand2, nxt,
                                                     strand)
                self.__strand_protector_neighbor_staple(
                    neighbor_stand1, neighbor_strand2, strand)
                self.__strand_connection_neighbor_staple(
                    neighbor_stand1, neighbor_strand2, strand, pool)

    def _get_triangle_pos(self):
        lst = []
        a = lst.append
        row, col = self.parent.pos
        a(row)
        a(col)
        if type(self) is TriangleLeft:
            a("L")
        else:
            a("R")
        return lst

    def __strand_protector_neighbor_staple(self, neighbor_stand1,
                                           neighbor_strand2, strand):
        if type(strand) is Protector and type(neighbor_stand1) is Staple:
            strand.short = neighbor_strand2.get_rev_c_or_none(
                StapleDomains.short)
            strand.long1 = neighbor_stand1.get_rev_c_or_none(
                StapleDomains.long2)
            strand.long2 = neighbor_stand1.get_rev_c_or_none(
                StapleDomains.long1)

    def __strand_staple_neighbor_staple(self, neighbor_stand1,
                                        neighbor_strand2, nxt, strand):
        if type(strand) is Staple and type(neighbor_stand1) is Staple:
            if not strand.long1:
                strand.long1 = neighbor_strand2.get_rev_c_or_none(
                    StapleDomains.short)
            if not strand.long2:
                strand.long2 = neighbor_stand1.get_rev_c_or_none(
                    StapleDomains.long2)
            # we can fill out also the next fragment of the next strand
            nxt_strand = self.get_staple_by_type(nxt[strand.type_id])
            if not nxt_strand.short:
                nxt_strand.short = neighbor_stand1.get_rev_c_or_none(
                    StapleDomains.long1)

    def __strand_connection_neighbor_staple(self,
                                            neighbor_strand1,
                                            neighbor_strand2,
                                            strand,
                                            pool=None):
        if type(strand) is ConnectionElement and type(
                neighbor_strand1) is Staple:
            # if it has an assigned sequence we need to assign the rev_c to the neighbors
            # for Connection elements all domains have to be filled out so we can check only 1 domain

            if neighbor_strand1.long1 and not strand.short:  # rely only on first neighbor
                #if neighbor_strand1.long1:  # rely only on first neighbor
                # the sequence based on the neighborhood (if they have a seq )
                strand.info = None
                strand.short = neighbor_strand2.get_rev_c_or_none(
                    StapleDomains.short)
                strand.long1 = neighbor_strand1.get_rev_c_or_none(
                    StapleDomains.long2)
                strand.long2 = neighbor_strand1.get_rev_c_or_none(
                    StapleDomains.long1)
            elif strand.info:
                return  #do nothing if we have already generated the sequences
            # TODO:check this section, as inner are now generated first
            # if not strand.short: #makes sure that we do have a seq
            #    # otherwise we assign a random seq and forward it to the neighbors
            #    strand.random_fill(pool)
            else:
                neighbor_strand2.info = None
                neighbor_strand1.info = None

                neighbor_strand2.short = strand.get_rev_c_or_none(
                    StapleDomains.short)
                neighbor_strand1.long2 = strand.get_rev_c_or_none(
                    StapleDomains.long1)
                neighbor_strand1.long1 = strand.get_rev_c_or_none(
                    StapleDomains.long2)

                neighbor_strand1.triangle.set_staple_by_type(
                    neighbor_strand1.type_id, neighbor_strand1)
                neighbor_strand2.triangle.set_staple_by_type(
                    neighbor_strand2.type_id, neighbor_strand2)

            # print("Connection strand looks like ")
            # print(strand)
            # print(strand.short is not None)

            # now we just need to change the seq for the to_protector if it does not have a seq (see #1)
            to_strand = strand.to_element
            print("*" * 80)
            print("to_strand", type(to_strand))
            if not to_strand.short:
                to_strand.info = None
                to_strand.short = neighbor_strand1.long1
                to_strand.long1 = neighbor_strand1.long2
                to_strand.long2 = neighbor_strand2.short
                # update the triangle
                to_strand.triangle.set_staple_by_type(to_strand.type_id,
                                                      to_strand)
Esempio n. 20
0
class PageViewer(QGraphicsView):
    mouseRelaseEvent = pyqtSignal()
    wheelZoomEvent = pyqtSignal()

    @property
    def drawing(self):
        return self._drawing

    @property
    def tool_mode(self):
        return self._toolMode

    @property
    def empty(self):
        return self._page is None

    @property
    def page_layer(self):
        return self._pageLayer

    @property
    def drawing_layer(self):
        return self._drawingLayer

    @property
    def page(self):
        return self._page

    @property
    def pen_size(self):
        return self._pen.width()

    @property
    def eraser_size(self):
        return self._eraserSize

    def __init__(self, parent):
        super(PageViewer, self).__init__(parent)

        self._page = None

        # todo: add all these constants to preferences dialog
        self._zoom = 0
        self._zoomMaxDistance = 10
        self._zoomInFactor = 1.25
        self._zoomOutFactor = 0.8
        self._panDivisor = 2
        self._toolMode = ToolMode.NOTHING
        self._previousToolModeDrag = ToolMode.NOTHING
        self._drawing = False
        self._dragStart = None
        self._drawPoint = None
        self._lastPenPos = None

        self._scene = QGraphicsScene(self)
        self._pageLayer = None
        self._drawingLayer = None

        self._predrawPixmap = None

        self._eraserSize = 100
        self._eraserEllipse = self.getEraserEllipse()

        pen_brush = QBrush(QColor('red'), Qt.SolidPattern)
        self._pen = QPen(pen_brush, 5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)

        self._increaseSizeAction = QAction('Increase tool size', self)
        self._increaseSizeAction.setEnabled(False)
        self._increaseSizeAction.triggered.connect(
            self.onIncreaseSizeActionTriggered)

        self._decreaseSizeAction = QAction('Decrease tool size', self)
        self._decreaseSizeAction.setEnabled(False)
        self._decreaseSizeAction.triggered.connect(
            self.onDecreaseSizeActionTriggered)

        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
        self.setMouseTracking(True)

    def reset(self):
        self.setInteractive(False)
        self.setToolMode(ToolMode.NOTHING)
        self.setScene(QGraphicsScene(self))

        self._page = None
        self._zoom = 0

    def getEraserEllipse(self):
        brush = QBrush(QColor(0, 0, 0, alpha=64), Qt.SolidPattern)
        pen = QPen(brush, 2, Qt.DashDotLine, Qt.RoundCap, Qt.RoundJoin)
        pen.setCosmetic(True)
        ellipse = QGraphicsEllipseItem(0, 0, self._eraserSize,
                                       self._eraserSize)
        ellipse.setPen(pen)
        return ellipse

    def fitPage(self):
        if not self.empty:
            rect = QRectF(self._pageLayer.pixmap().rect())
            if not rect.isNull():
                self.setSceneRect(rect)
                unity = self.transform().mapRect(QRectF(0, 0, 1, 1))
                self.scale(1 / unity.width(), 1 / unity.height())
                viewrect = self.viewport().rect()
                scenerect = self.transform().mapRect(rect)
                factor = min(viewrect.width() / scenerect.width(),
                             viewrect.height() / scenerect.height())
                self.scale(factor, factor)
                self._zoom = 0

    def setPage(self, page):
        self._page = page

        if not self._page.page_image.isNull():
            self._scene.clear()

            self._pageLayer = QGraphicsPixmapItem(self._page.page_image)
            self._scene.addItem(self._pageLayer)
            self._drawingLayer = QGraphicsPixmapItem(self._page.drawing_image)
            self._scene.addItem(self._drawingLayer)

            self.fitPage()
            self._eraserEllipse = self.getEraserEllipse()
            self.setScene(self._scene)
            self.setToolMode(self._toolMode)
            self.setInteractive(True)

    def canZoomIn(self):
        return self._zoom < self._zoomMaxDistance

    def canZoomOut(self):
        return self._zoom > 0

    def zoomIn(self):
        if self.canZoomIn():
            self._zoom += 1
            self._applyZoom(self._zoomInFactor)
            return True
        return False

    def zoomOut(self):
        if self.canZoomOut():
            self._zoom -= 1
            self._applyZoom(self._zoomOutFactor)
            return True
        return False

    def _applyZoom(self, factor):
        if self._zoom > 0:
            self.scale(factor, factor)
        else:
            self._zoom = 0
            self.fitPage()

    def wheelEvent(self, event):
        if not self.empty:
            if event.angleDelta().y() > 0:
                factor = self._zoomInFactor
                if not self.zoomIn():
                    return
            else:
                factor = self._zoomOutFactor
                self.zoomOut()

            self._applyZoom(factor)
            self.wheelZoomEvent.emit()

    def _penDraw(self, pos):
        self._drawing = True
        self._lastPenPos = self._drawPoint
        self._drawPoint = pos
        self.update()

    def _eraseDraw(self, pos):
        self._drawing = True
        self._drawPoint = pos
        self.update()

    def mousePressEvent(self, event):
        if not self.empty:
            button = event.button()
            scenePos = self.mapToScene(event.pos())

            if button == Qt.MiddleButton:
                self._previousToolModeDrag = self._toolMode
                self.setToolMode(ToolMode.DRAGGING)
                self._dragStart = scenePos
            elif button == Qt.LeftButton:
                if self._toolMode == ToolMode.NOTHING:
                    self.setToolMode(ToolMode.DRAGGING)
                else:
                    sceneRect = self._drawingLayer.mapRectToScene(
                        QRectF(self._page.drawing_image.rect()))

                    if sceneRect.contains(scenePos.x(), scenePos.y()):
                        self._predrawPixmap = copyPixmap(
                            self._page.drawing_image)
                        if self._toolMode == ToolMode.PEN:
                            self._penDraw(scenePos)
                        if self._toolMode == ToolMode.ERASER:
                            self._eraseDraw(scenePos)

        super(PageViewer, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        scenePos = self.mapToScene(event.pos())

        if self._toolMode == ToolMode.ERASER:
            r = self._eraserEllipse.rect()
            x = scenePos.x() - (r.width() / 2)
            y = scenePos.y() - (r.height() / 2)
            self._eraserEllipse.setPos(x, y)

        if not self.empty:
            if self._toolMode == ToolMode.DRAGGING and self._dragStart is not None:
                delta = self.mapToScene(event.pos())
                self.translate(delta.x() - self._dragStart.x(),
                               delta.y() - self._dragStart.y())
            else:
                if self._drawing:
                    if self._toolMode == ToolMode.PEN:
                        self._penDraw(scenePos)

        super(PageViewer, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        if not self.empty:
            button = event.button()
            scenePos = self.mapToScene(event.pos())

            if button == Qt.MiddleButton:
                self.setToolMode(self._previousToolModeDrag)
            elif button == Qt.LeftButton:
                if self._toolMode == ToolMode.DRAGGING:
                    self.setToolMode(ToolMode.NOTHING)
                elif self._toolMode == ToolMode.PEN:
                    self._penDraw(scenePos)
                    self._page.pushCommand(
                        DrawCommand(self, self._predrawPixmap))
                    self._lastPenPos = None
                elif self._toolMode == ToolMode.ERASER:
                    self._eraseDraw(scenePos)
                    self._page.pushCommand(
                        DrawCommand(self, self._predrawPixmap))

                self._drawPoint = None
                self._drawing = False

        self.mouseRelaseEvent.emit()

    def paintEvent(self, event):
        if self._drawing:
            painter = QPainter(self._page.drawing_image)
            painter.setRenderHint(QPainter.HighQualityAntialiasing, True)

            if self._toolMode == ToolMode.ERASER:
                painter.setPen(Qt.NoPen)
                painter.setBrush(painter.background())

                r = int(self._eraserSize / 2)
                painter.drawEllipse(self._drawPoint, r, r)

            if self._toolMode == ToolMode.PEN:
                painter.setPen(self._pen)

                if self._lastPenPos is None:
                    painter.drawPoint(self._drawPoint)
                else:
                    painter.drawLine(self._lastPenPos, self._drawPoint)

            painter.end()
            self.updateDrawingLayer()

        super(PageViewer, self).paintEvent(event)

    def setToolMode(self, mode: ToolMode):
        self._toolMode = mode

        self._increaseSizeAction.setEnabled(False)
        self._decreaseSizeAction.setEnabled(False)

        for item in self._scene.items():
            if isinstance(item, QGraphicsEllipseItem):
                self._scene.removeItem(item)

        if self._toolMode == ToolMode.DRAGGING:
            self.setCursor(Qt.ClosedHandCursor)
        else:
            if self._toolMode == ToolMode.ERASER:
                self._scene.addItem(self._eraserEllipse)

                self._increaseSizeAction.setText('Increase Eraser width')
                self._decreaseSizeAction.setText('Decrease Eraser width')
                self._increaseSizeAction.setEnabled(True)
                self._decreaseSizeAction.setEnabled(True)
            elif self._toolMode == ToolMode.PEN:
                self.setDragMode(QGraphicsView.NoDrag)
                self.setCursor(Qt.CrossCursor)

                self._increaseSizeAction.setText('Increase Pen width')
                self._decreaseSizeAction.setText('Decrease Pen width')
                self._increaseSizeAction.setEnabled(True)
                self._decreaseSizeAction.setEnabled(True)
            else:
                self.setDragMode(QGraphicsView.NoDrag)
                self.setCursor(Qt.ArrowCursor)

    def setEraserSize(self, v):
        if 500 >= v >= 10:
            self._eraserEllipse.setRect(0, 0, v, v)
            self._eraserSize = v

    def setPenSize(self, v):
        if 30 >= v > 0:
            self._pen.setWidth(v)

    def onIncreaseSizeActionTriggered(self):
        if self._toolMode == ToolMode.ERASER:
            v = self._eraserSize + 1
            self.setEraserSize(v)
        elif self._toolMode == ToolMode.PEN:
            v = self._pen.width() + 1
            self.setPenSize(v)

    def onDecreaseSizeActionTriggered(self):
        if self._toolMode == ToolMode.ERASER:
            v = self._eraserSize - 1
            self.setEraserSize(v)
        elif self._toolMode == ToolMode.PEN:
            v = self._pen.width() - 1
            self.setPenSize(v)

    def getActiveToolSizeText(self):
        if self._toolMode == ToolMode.ERASER:
            return '{:03d}px'.format(self._eraserSize)
        elif self._toolMode == ToolMode.PEN:
            return '{:02d}px'.format(self._pen.width())
        else:
            return ''

    def getIncreaseSizeAction(self):
        return self._increaseSizeAction

    def getDecreaseSizeAction(self):
        return self._decreaseSizeAction

    def updateDrawingLayer(self):
        self._drawingLayer.setPixmap(self._page.drawing_image)
Esempio n. 21
0
class RenderArea(QWidget):
    """
    Класс области рисования
    """
    def __init__(self, parent=None):
        super(RenderArea, self).__init__(parent)

        self.sphere = Sphere(self)

        self.pen = QPen(QColor(0, 0, 0), 0)
        self.faces_color = QColor(0, 255, 0)
        self.is_light = False
        self.is_clipping = False

        self.setBackgroundRole(QPalette.Base)
        self.setAutoFillBackground(True)

    def minimumSizeHint(self):
        return QSize(200, 200)

    def sizeHint(self):
        return QSize(400, 400)

    def set_pen_width(self, width):
        self.pen = QPen(self.pen.color(), width)
        self.update()

    def set_pen_color(self, label):
        color = QColorDialog.getColor()
        if color.isValid():
            self.pen = QPen(color, self.pen.width())
            label_palette = QPalette()
            label_palette.setColor(QPalette.WindowText, color)
            label.setPalette(label_palette)
            label.setText("Цвет линии " + color.name())
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setPen(self.pen)

        # Пересчитываем сферу
        self.sphere.recalculate()

        # Рисуем
        for face in self.sphere.geom.faces:
            self.draw_item(face, painter)

        # Окантовка виджета
        painter.setPen(self.palette().dark().color())
        painter.setBrush(Qt.NoBrush)
        painter.drawRect(QRect(0, 0, self.width() - 1, self.height() - 1))

    def draw_item(self, face, painter):
        is_draw = True
        if self.is_clipping:
            is_draw = self.sphere.is_face_visible(face)
        if is_draw:
            polygon = QPolygon()
            for index, point_index in enumerate(face):
                p1_x = int(self.sphere.geom.points[face[index - 1]][0])
                p1_y = int(self.sphere.geom.points[face[index - 1]][1])
                p1_z = int(self.sphere.geom.points[face[index - 1]][2])

                p2_x = int(self.sphere.geom.points[point_index][0])
                p2_y = int(self.sphere.geom.points[point_index][1])
                p2_z = int(self.sphere.geom.points[point_index][2])

                if self.sphere.projection_name == "front":
                    # Фронтальная проекция (вид спереди) -> z = 0
                    real_p1 = QPoint(p1_x, p1_y)
                    real_p2 = QPoint(p2_x, p2_y)
                elif self.sphere.projection_name == "horizontal":
                    # Горизонтальная проекция (вид сверху) -> y = 0
                    real_p1 = QPoint(p1_x, p1_z)
                    real_p2 = QPoint(p2_x, p2_z)
                elif self.sphere.projection_name == "profile":
                    # Профильная проекция (вид сбоку) -> x = 0
                    real_p1 = QPoint(p1_y, p1_z)
                    real_p2 = QPoint(p2_y, p2_z)
                else:
                    real_p1 = QPoint(p1_x, p1_y)
                    real_p2 = QPoint(p2_x, p2_y)

                # Точки для проволочного рисования
                real_p1.setX(self.width() / 2 + real_p1.x())
                real_p1.setY(self.height() / 2 - real_p1.y())
                real_p2.setX(self.width() / 2 + real_p2.x())
                real_p2.setY(self.height() / 2 - real_p2.y())

                # Полигоны для рисования с цветом
                polygon.append(real_p1)
                polygon.append(real_p2)

                if not self.is_light:
                    painter.drawLine(real_p1, real_p2)

            if self.is_light:

                painter.setBrush(
                    self.sphere.get_face_light(face, self.faces_color))
                painter.drawPolygon(polygon)

    def set_projection(self, button):
        self.sphere.projection_name = button.objectName()
        self.update()

    def set_clipping(self, state):
        self.is_clipping = True if state == Qt.Checked else False
        self.update()

    def set_faces_color(self, label):
        color = QColorDialog.getColor()
        if color.isValid():
            self.faces_color = color
            label_palette = QPalette()
            label_palette.setColor(QPalette.WindowText, color)
            label.setPalette(label_palette)
            label.setText("Цвет объекта " + color.name())
        self.update()

    def set_light(self, is_light, clipping_checkbox):
        self.is_light = is_light
        clipping_checkbox.setChecked(self.is_light)
        clipping_checkbox.setDisabled(self.is_light)
        self.update()
Esempio n. 22
0
class LinkGI(QGraphicsPathItem):
    def __init__(self, name, srcSocket, dstSocket, thickness=2):
        super().__init__()

        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setAcceptHoverEvents(True)
        self.hovering = False

        self.linkName = name
        self.srcSocket = srcSocket
        self.dstSocket = dstSocket
        self.srcSocket.link = self
        self.dstSocket.link = self

        self.updateShape()

        # set the pen style
        self.linkPen = QPen()
        self.linkPen.setWidth(thickness)
        self.linkPen.setCapStyle(Qt.RoundCap)
        self.linkPen.setColor(schemastyle.LINK_COLOR)
        self.setPen(self.linkPen)

    def updateShape(self):
        # Create the bezier curve path
        srcX, srcY = self.srcSocket.linkConnectionPos()
        dstX, dstY = self.dstSocket.linkConnectionPos()
        linkPath = QPainterPath()
        linkPath.setFillRule(Qt.WindingFill)
        linkPath.moveTo(srcX, srcY)
        linkPath.cubicTo(srcX + 100, srcY, dstX - 100, dstY, dstX, dstY)

        self.setPath(linkPath)

    def hoverEnterEvent(self, event):
        self.linkPen.setColor(QColor(Qt.white))
        self.setPen(self.linkPen)
        super().hoverEnterEvent(event)

    def hoverLeaveEvent(self, event):
        self.linkPen.setColor(QColor(Qt.gray))
        self.setPen(self.linkPen)
        super().hoverLeaveEvent(event)

    @property
    def name(self):
        return self.linkName

    @name.setter
    def name(self, name):
        self.linkName = name
        self.update()

    @property
    def thickness(self):
        return self.linkPen.width()

    @thickness.setter
    def thickness(self, thickness):
        self.linkPen.setWidth(thickness)
        self.setPen(self.linkPen)
        self.update()