示例#1
0
    def paintEvent(self, event):
        # Draw backgrounds according to css
        styleOpt = QStyleOption()
        styleOpt.initFrom(self)
        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing)
        self.style().drawPrimitive(QStyle.PE_Widget, styleOpt, p, self)

        if self.values == None or len(self.values) == 0: return

        # print(len(self.values))

        r = self.rect()
        dx = r.width() / float(self.datapoints - 1)

        # Build a path from the readings
        path = QPainterPath()
        path.moveTo(r.bottomRight())
        i = 0
        for reading in reversed(self.values):
            pt = QPointF(r.width() - i*dx, (1.0 - reading) * r.height())
            path.lineTo(pt)
            i = i + 1
        path.lineTo(path.currentPosition().x(), r.height())
        path.closeSubpath()

        # Use foreground color for graph
        gcolor = styleOpt.palette.color(QPalette.Text)
        p.setBrush(gcolor)
        p.setPen(gcolor)
        p.drawPath(path)
示例#2
0
    def paintEvent(self, event):
        rect = QRect(10, 20, 80, 60)

        path = QPainterPath()
        path.moveTo(20, 80)
        path.lineTo(20, 30)
        path.cubicTo(80, 0, 50, 50, 80, 80)

        startAngle = 30 * 16
        arcLength = 120 * 16

        painter = QPainter(self)
        painter.setPen(self.pen)
        painter.setBrush(self.brush)
        if self.antialiased:
            painter.setRenderHint(QPainter.Antialiasing)

        for x in range(0, self.width(), 100):
            for y in range(0, self.height(), 100):
                painter.save()
                painter.translate(x, y)
                if self.transformed:
                    painter.translate(50, 50)
                    painter.rotate(60.0)
                    painter.scale(0.6, 0.9)
                    painter.translate(-50, -50)

                if self.shape == RenderArea.Line:
                    painter.drawLine(rect.bottomLeft(), rect.topRight())
                elif self.shape == RenderArea.Points:
                    painter.drawPoints(RenderArea.points)
                elif self.shape == RenderArea.Polyline:
                    painter.drawPolyline(RenderArea.points)
                elif self.shape == RenderArea.Polygon:
                    painter.drawPolygon(RenderArea.points)
                elif self.shape == RenderArea.Rect:
                    painter.drawRect(rect)
                elif self.shape == RenderArea.RoundedRect:
                    painter.drawRoundedRect(rect, 25, 25, Qt.RelativeSize)
                elif self.shape == RenderArea.Ellipse:
                    painter.drawEllipse(rect)
                elif self.shape == RenderArea.Arc:
                    painter.drawArc(rect, startAngle, arcLength)
                elif self.shape == RenderArea.Chord:
                    painter.drawChord(rect, startAngle, arcLength)
                elif self.shape == RenderArea.Pie:
                    painter.drawPie(rect, startAngle, arcLength)
                elif self.shape == RenderArea.Path:
                    painter.drawPath(path)
                elif self.shape == RenderArea.Text:
                    painter.drawText(rect, Qt.AlignCenter,
                            "PyQt by\nRiverbank Computing")
                elif self.shape == RenderArea.Pixmap:
                    painter.drawPixmap(10, 10, self.pixmap)

                painter.restore()

        painter.setPen(self.palette().dark().color())
        painter.setBrush(Qt.NoBrush)
        painter.drawRect(QRect(0, 0, self.width() - 1, self.height() - 1))
示例#3
0
def _get_pos_widget(name, backgroundColor, foregroundColor):
    label = QLabel()
    label.setAttribute(Qt.WA_TransparentForMouseEvents, True)

    pixmap = QPixmap(25 * 10, 25 * 10)
    pixmap.fill(backgroundColor)
    painter = QPainter()
    painter.begin(pixmap)
    pen = QPen(foregroundColor)
    painter.setPen(pen)
    painter.setRenderHint(QPainter.Antialiasing)
    font = QFont()
    font.setBold(True)
    font.setPixelSize(25 * 10 - 30)
    path = QPainterPath()
    path.addText(QPointF(50, 25 * 10 - 50), font, name)
    brush = QBrush(foregroundColor)
    painter.setBrush(brush)
    painter.drawPath(path)
    painter.setFont(font)
    painter.end()
    pixmap = pixmap.scaled(QSize(20, 20), Qt.KeepAspectRatio, Qt.SmoothTransformation)
    label.setPixmap(pixmap)

    spinbox = DelayedSpinBox(750)
    spinbox.setAlignment(Qt.AlignCenter)
    spinbox.setToolTip("{0} Spin Box".format(name))
    spinbox.setButtonSymbols(QAbstractSpinBox.NoButtons)
    spinbox.setMaximumHeight(20)
    font = spinbox.font()
    font.setPixelSize(14)
    spinbox.setFont(font)
    sheet = TEMPLATE.format(foregroundColor.name(), backgroundColor.name())
    spinbox.setStyleSheet(sheet)
    return label, spinbox
示例#4
0
    def paintEvent(self, event):
        # Check whether this orb is enhanced
        if type(self.parent) == Board:
            enh = self.parent.enhanced[self.position]
        else:
            enh = False

        painter = QPainter(self)
        painter.drawPixmap(event.rect().adjusted(2,2,-2,-2), self.pixmap())

        w = event.rect().width()

        if enh:
            path = QPainterPath()

            pen = QPen()
            pen.setWidth(1);
            pen.setBrush(Qt.white)

            brush = QBrush(Qt.yellow)

            font = QFont()
            font.setPointSize(20)
            font.setWeight(QFont.Black)
            
            path.addText(event.rect().x()+w-15,event.rect().y()+w-5,font,'+')

            painter.setPen(pen)
            painter.setBrush(brush)
            painter.setFont(font)

            painter.drawPath(path)
示例#5
0
class ModCrossButton(QPushButton):
    def __init__(self,parent,path=None):
        QPushButton.__init__(self,parent)

        self.parent=parent


        #self.setAttribute(Qt.WA_TranslucentBackground, True)
        self.backgroundColor = QPalette().light().color()
        self.backgroundColor.setRgb(157,157,157) #(220,203,231)
        #self.backgroundColor.setAlpha(100)
        self.brush=QBrush(Qt.SolidPattern)


    def paintEvent(self,event):
        self.wide=self.width()
        self.high=self.height()
        self.xdis=self.wide/7
        self.ydis=self.xdis

        self.path=QPainterPath()
        self.path.setFillRule(Qt.OddEvenFill)

        self.path.moveTo(self.wide/2, self.high/2-self.xdis)
        self.path.arcTo(0,0, self.wide, self.high,0,360)
        #self.path.closeSubpath()

        self.path.moveTo(self.wide/2-self.xdis/2, self.ydis)
        self.path.lineTo(self.wide/2-self.xdis/2, self.high/2-self.xdis/2)
        self.path.lineTo(self.ydis, self.high/2-self.xdis/2)
        self.path.lineTo(self.ydis, self.high/2+self.xdis/2)
        self.path.lineTo(self.wide/2-self.xdis/2, self.high/2+self.xdis/2)
        self.path.lineTo(self.wide/2-self.xdis/2, self.high-self.ydis)
        self.path.lineTo(self.wide/2+self.xdis/2, self.high-self.ydis)
        self.path.lineTo(self.wide/2+self.xdis/2, self.high/2+self.xdis/2)
        self.path.lineTo(self.wide-self.ydis, self.high/2+self.xdis/2)
        self.path.lineTo(self.wide-self.ydis, self.high/2-self.xdis/2)
        self.path.lineTo(self.wide/2+self.xdis/2, self.high/2-self.xdis/2)
        self.path.lineTo(self.wide/2+self.xdis/2, self.ydis)
        self.path.closeSubpath()

        self.brush.setColor(self.backgroundColor)
        self.painter=QPainter(self)
        self.painter.setRenderHint(QPainter.Antialiasing)

        self.painter.setPen(Qt.NoPen)
        self.painter.setBrush(self.brush)
        self.painter.drawPath(self.path)
        self.painter.end()

    #def mousePressEvent(self,ev):
    #    self.parent.close()

    def enterEvent(self,ev):
        self.backgroundColor.setRgb(242,146,52) 
        self.update()
        
    def leaveEvent(self,ev):
        self.backgroundColor.setRgb(157,157,157)
        self.update()
示例#6
0
 def paintEvent(self, event):
     painter = QPainter(self)
     painter.setRenderHint(QPainter.Antialiasing)
     for shapeItem in self.shapeItems:
         painter.translate(shapeItem.position())
         painter.setBrush(shapeItem.color())
         painter.drawPath(shapeItem.path())
         painter.translate(-shapeItem.position())
示例#7
0
class ModCloseButton(QPushButton):
    def __init__(self,parent,wide,high,ppath=None):
        QPushButton.__init__(self,parent)

        self.parent=parent
        self.wide=wide
        self.high=high
        self.resize(self.wide,self.high)
        self.xdis=self.wide/10

        #self.setAttribute(Qt.WA_TranslucentBackground, True)
        self.backgroundColor = QPalette().light().color()
        self.backgroundColor.setRgb(157,157,157) #(220,203,231)
        #self.backgroundColor.setAlpha(100)
        self.brush=QBrush(Qt.SolidPattern)

        if ppath :
            self.path=ppath
        else :
            self.path=QPainterPath()

            self.path.moveTo(self.wide/2, self.high/2-self.xdis)
            self.path.arcTo(0,0, self.wide-2*self.xdis, self.high-2*self.xdis,45,90)
            self.path.closeSubpath()

            self.path.moveTo(self.wide/2-self.xdis, self.high/2)
            self.path.arcTo(0,0,self.wide-2*self.xdis,self.high-2*self.xdis,135,90)
            self.path.closeSubpath()

            self.path.moveTo(self.wide/2, self.high/2+self.xdis)
            self.path.arcTo(0,0,self.wide-2*self.xdis, self.high-2*self.xdis,225,90)
            self.path.closeSubpath()

            self.path.moveTo(self.wide/2+self.xdis, self.high/2)
            self.path.arcTo(0,0,self.wide-2*self.xdis, self.high-2*self.xdis,315,90)
            self.path.closeSubpath()

    def paintEvent(self,event):
        self.brush.setColor(self.backgroundColor)
        self.painter=QPainter(self)
        self.painter.setRenderHint(QPainter.Antialiasing)

        self.painter.setPen(Qt.NoPen)
        self.painter.setBrush(self.brush)
        self.painter.drawPath(self.path)
        self.painter.end()

    def mousePressEvent(self,ev):
        self.parent.close()

    def enterEvent(self,ev):
        self.backgroundColor.setRgb(234,39,13) 
        self.update()
        
    def leaveEvent(self,ev):
        self.backgroundColor.setRgb(157,157,157)
        self.update()
示例#8
0
 def paintEvent(self, event):
 
     painter = QPainter()
     painter.begin(self)
     painter.setRenderHint(QPainter.Antialiasing)
     painter.setBrush(QBrush(QColor(192, 192, 255)))
     painter.drawRect(event.rect())
     
     painter.translate(self.width()/2.0, self.height()/2.0)
     painter.rotate(self._angle)
     painter.setBrush(QBrush(self.gradient))
     painter.drawPath(self.path)
     painter.end()
示例#9
0
 def paintEvent(self, event):
     painter = QPainter(self)
     painter.setBrush(self.brush)
     if self.opacity is None or self.parent().vanishing:
         painter.setOpacity(self.parent().opacity / 255)
     else:
         painter.setOpacity(self.opacity / 255)
     pen = QPen(QColor(100, 100, 100, 150))
     pen.setWidth(10)
     painter.setPen(pen)
     painter.drawPath(self.path)
     painter.setPen(QColor(0, 0, 0))
     painter.drawText(self.path.controlPointRect(), Qt.AlignCenter, self.name)
示例#10
0
 def _drawTextShadow(self, painter: QPainter, x: int, y: int, text: str):
     font = self.font()
     # setup outline path
     text_path = QPainterPath()
     text_path.addText(x, y, font, text)
     # draw outline path 1
     painter.setPen(self.outline_pen)
     painter.setBrush(self.outline_brush)
     painter.drawPath(text_path)
     # draw text
     painter.setPen(self.text_color)
     painter.setFont(font)
     # Note: The y-position is used as the baseline of the font.
     painter.drawText(x, y, text)
示例#11
0
 def _drawOutlinedText(painter: QPainter, x: int, y: int, text: str,
                      font: QFont, textColor: QColor, outlineColor: QColor, outlineWidth: int=1):
     # setup outline path
     text_path = QPainterPath()
     text_path.addText(x, y, font, text)
     # draw outline path
     outlineBrush = QBrush(outlineColor, Qt.SolidPattern)
     outlinePen = QPen(outlineBrush, outlineWidth, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
     painter.setPen(outlinePen)
     painter.setBrush(outlineBrush)
     painter.drawPath(text_path)
     # draw text
     painter.setPen(textColor)
     painter.setFont(font)
     painter.drawText(x, y, text)
示例#12
0
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.scale(self.width() / 100.0, self.height() / 100.0)
        painter.translate(50.0, 50.0)
        painter.rotate(-self.rotationAngle)
        painter.translate(-50.0, -50.0)

        painter.setPen(
                QPen(self.penColor, self.penWidth, Qt.SolidLine, Qt.RoundCap,
                        Qt.RoundJoin))
        gradient = QLinearGradient(0, 0, 0, 100)
        gradient.setColorAt(0.0, self.fillColor1)
        gradient.setColorAt(1.0, self.fillColor2)
        painter.setBrush(QBrush(gradient))
        painter.drawPath(self.path)
示例#13
0
 def createAxisLabelPixmap(self):
     pixmap = QPixmap(250, 250)
     pixmap.fill(self.backgroundColor)
     painter = QPainter()
     painter.begin(pixmap)
     font = QFont()
     font.setBold(True)
     font.setPixelSize(250 - 30)
     path = QPainterPath()
     path.addText(QPointF(50, 250 - 50), font, self.axis)
     brush = QBrush(self.foregroundColor)
     painter.setBrush(brush)
     painter.drawPath(path)
     painter.setFont(font)
     painter.end()
     pixmap = pixmap.scaled(QSize(self.labelsWidth, self.labelsheight), Qt.KeepAspectRatio, Qt.SmoothTransformation)
     return pixmap
示例#14
0
文件: qt.py 项目: gitter-badger/eddy
 def __init__(self, width, height, color, border=None):
     """
     Initialize the icon.
     :type width: T <= int | float
     :type height: T <= int | float
     :type color: str
     :type border: str
     """
     pixmap = QPixmap(width, height)
     painter = QPainter(pixmap)
     painter.setRenderHint(QPainter.Antialiasing)
     path = QPainterPath()
     path.addRect(QRectF(QPointF(0, 0), QPointF(width, height)))
     painter.fillPath(path, QBrush(QColor(color)))
     if border:
         painter.setPen(QPen(QColor(border), 0, Qt.SolidLine))
         painter.drawPath(path)
     painter.end()
     super().__init__(pixmap)
示例#15
0
    def paint(self, painter: QPainter):
        painter_path = QPainterPath()
        painter_path.moveTo(self._startX, self._startY)
        x1 = (7 * self._endX + self._startX) / 8
        y1 = self._startY
        x2 = (self._endX + 7 * self._startX) / 8
        y2 = self._endY
        painter_path.cubicTo(x1, y1, x2, y2, self._endX, self._endY)

        if self._startArrow:
            self.add_arrow(self._startX, self._startY, 'l' if self._startX <= self._endX else 'r',painter_path)

        if self._endArrow:
            self.add_arrow(self._endX, self._endY,  'r' if self._startX <= self._endX else 'l',painter_path)

        pen = QPen(self._color, self._curveWidth, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        painter.setPen(pen)
        painter.setRenderHints(QPainter.Antialiasing, True)
        painter.drawPath(painter_path)
示例#16
0
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        self._optionsRects = {}
        w, h = self.width(), self.height()
        metrics = self.fontMetrics()
        hphp = 2 * _hPad

        painter.save()
        path = QPainterPath()
        path.addRoundedRect(.5, .5, w - 1, h - 1, 4, 4)
        painter.fillPath(path, QColor(250, 250, 250))
        x = 0
        linePath = QPainterPath()
        for text in self._options[:-1]:
            x += hphp + metrics.width(text)
            linePath.moveTo(x, 0)
            linePath.lineTo(x, h)
        pen = painter.pen()
        pen.setColor(QColor(218, 218, 218))
        pen.setWidth(0)
        painter.setPen(pen)
        painter.drawPath(path)
        painter.setRenderHint(QPainter.Antialiasing, False)
        painter.drawPath(linePath)
        painter.restore()

        painter.translate(_hPad, _vPad + metrics.ascent())
        left = 0
        for index, text in enumerate(self._options):
            if index in self._selection:
                color = QColor(20, 146, 230)
            else:
                color = QColor(63, 63, 63)
            painter.setPen(color)
            painter.drawText(0, 0, text)
            textWidth = metrics.width(text)
            rectWidth = textWidth + hphp
            rect = (left, 0, rectWidth, h)
            self._optionsRects[index] = rect
            painter.translate(rectWidth, 0)
            left += rectWidth
示例#17
0
def create_rounded_image(pixmap):
    color = QColor(0, 0, 0, 0)
    pix = QPixmap(QSize(pixmap.width(), pixmap.height()))
    pix.fill(color)

    rect = QRectF(0.0, 0.0, pixmap.width(), pixmap.height())
    painter = QPainter()
    painter.begin(pix)
    painter.setRenderHints(QPainter.Antialiasing, True)
    path = QPainterPath()
    path.addRoundedRect(rect, pixmap.width() / 2, pixmap.height() / 2)
    painter.drawPath(path)

    brush = QtGui.QBrush()
    brush.setTexture(pixmap)

    painter.fillPath(path, brush)
    painter.end()

    return pix
示例#18
0
 def _drawTextShadow(painter: QPainter, x: int, y: int, text: str, font: QFont, text_color: QColor):
     # setup outline path
     text_path = QPainterPath()
     text_path.addText(x, y, font, text)
     # draw outline path 1
     outline_color = QColor(0, 0, 0, 64)
     outline_brush = QBrush(outline_color, Qt.SolidPattern)
     outline_pen = QPen(outline_brush, 8, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
     painter.setPen(outline_pen)
     painter.setBrush(outline_brush)
     painter.drawPath(text_path)
     # draw outline path 2
     outline_color = QColor(0, 0, 0, 128)
     outline_brush = QBrush(outline_color, Qt.SolidPattern)
     outline_pen = QPen(outline_brush, 4, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
     painter.setPen(outline_pen)
     painter.setBrush(outline_brush)
     painter.drawPath(text_path)
     # draw text
     painter.setPen(text_color)
     painter.setFont(font)
     painter.drawText(x, y, text)
示例#19
0
    def paintEvent(self, event):
        self._alignmentPaths = []
        painter = QPainter(self)
        painter.setPen(QColor(45, 45, 45))

        circleRadius = self._circleRadius
        padding = self._padding
        rect = event.rect()
        size = min(rect.height(), rect.width())
        offset = .5 * (rect.width() - size)
        painter.translate(offset, 0)
        borderRect = rect.__class__(
            rect.left() + circleRadius + padding,
            rect.top() + circleRadius + padding,
            size - 2 * (circleRadius + padding),
            size - 2 * (circleRadius + padding))
        borderPath = QPainterPath()
        borderPath.addRect(*borderRect.getRect())

        columnCount = 3
        radioPath = QPainterPath()
        selectedPath = QPainterPath()
        for row in range(columnCount):
            for col in range(columnCount):
                index = row * columnCount + col
                path = QPainterPath()
                path.addEllipse(
                    padding + col * .5 * borderRect.width(),
                    padding + row * .5 * borderRect.height(),
                    2 * circleRadius, 2 * circleRadius)
                if self._alignment == index:
                    selectedPath = path
                self._alignmentPaths.append(path.translated(offset, 0))
                radioPath.addPath(path)
        painter.drawPath(borderPath - radioPath)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.drawPath(radioPath)
        painter.fillPath(selectedPath, Qt.black)
示例#20
0
 def paintEvent(self, evt):
     """
     Protected method handling a paint event.
     
     @param evt reference to the paint event (QPaintEvent)
     """
     painter = QPainter(self)
     
     if self.__image is not None and not self.__image.isNull():
         x = (self.width() - self.__image.width()) // 2 - 1
         y = (self.height() - self.__image.height()) // 2 - 1
         painter.drawImage(x, y, self.__image)
     
     if self.__menu is not None:
         triagPath = QPainterPath()
         startPos = QPointF(self.width() - 5, self.height() - 3)
         triagPath.moveTo(startPos)
         triagPath.lineTo(startPos.x() + 4, startPos.y())
         triagPath.lineTo(startPos.x() + 2, startPos.y() + 2)
         triagPath.closeSubpath()
         painter.setPen(Qt.black)
         painter.setBrush(Qt.black)
         painter.setRenderHint(QPainter.Antialiasing, False)
         painter.drawPath(triagPath)
示例#21
0
    def toPdf(self, image):
        printer = QPrinter()
        printer.setPaperSize(QSizeF(210, 297), QPrinter.Millimeter)
        printer.setResolution(600)
        printer.setOutputFormat(QPrinter.PdfFormat)
        printer.setOutputFileName(self.get_path_to_revealer_file('.pdf'))
        printer.setPageMargins(0,0,0,0,6)
        painter = QPainter()
        painter.begin(printer)

        delta_h = round(image.width()/self.abstand_v)
        delta_v = round(image.height()/self.abstand_h)

        size_h = 2028+((int(self.calibration_h)*2028/(2028-(delta_h*2)+int(self.calibration_h)))/2)
        size_v = 1284+((int(self.calibration_v)*1284/(1284-(delta_v*2)+int(self.calibration_v)))/2)

        image =  image.scaled(size_h, size_v)

        painter.drawImage(553,533, image)
        wpath = QPainterPath()
        wpath.addRoundedRect(QRectF(553,533, size_h, size_v), 19, 19)
        painter.setPen(QPen(Qt.black, 1))
        painter.drawPath(wpath)
        painter.end()
示例#22
0
    def paintEvent(self, event):
        qp = QPainter()
        qp.begin(self)
        qp.setPen(self.textColor)
        qp.setFont(self.font)
        qp.setRenderHint(QPainter.Antialiasing)
        w = 0
        # Draw time
        scale = self.getScale()
        while w <= self.width():
            qp.drawText(w - 50, 0, 100, 100, Qt.AlignHCenter,
                        self.get_time_string(w * scale))
            w += 100
        # Draw down line
        qp.setPen(QPen(Qt.darkCyan, 5, Qt.SolidLine))
        qp.drawLine(0, 40, self.width(), 40)

        # Draw dash lines
        point = 0
        qp.setPen(QPen(self.textColor))
        qp.drawLine(0, 40, self.width(), 40)
        while point <= self.width():
            if point % 30 != 0:
                qp.drawLine(3 * point, 40, 3 * point, 30)
            else:
                qp.drawLine(3 * point, 40, 3 * point, 20)
            point += 10

        if self.pos is not None and self.is_in:
            qp.drawLine(self.pos.x(), 0, self.pos.x(), 40)

        if self.pointerPos is not None:
            line = QLine(
                QPoint(self.pointerTimePos / self.getScale(), 40),
                QPoint(self.pointerTimePos / self.getScale(), self.height()))
            poly = QPolygon([
                QPoint(self.pointerTimePos / self.getScale() - 10, 20),
                QPoint(self.pointerTimePos / self.getScale() + 10, 20),
                QPoint(self.pointerTimePos / self.getScale(), 40)
            ])
        else:
            line = QLine(QPoint(0, 0), QPoint(0, self.height()))
            poly = QPolygon([QPoint(-10, 20), QPoint(10, 20), QPoint(0, 40)])

        # Draw samples
        t = 0
        for sample in self.videoSamples:
            # Clear clip path
            path = QPainterPath()
            path.addRoundedRect(
                QRectF(t / scale, 50, sample.duration / scale, 200), 10, 10)
            qp.setClipPath(path)

            # Draw sample
            path = QPainterPath()
            qp.setPen(sample.color)
            path.addRoundedRect(
                QRectF(t / scale, 50, sample.duration / scale, 50), 10, 10)
            sample.startPos = t / scale
            sample.endPos = t / scale + sample.duration / scale
            qp.fillPath(path, sample.color)
            qp.drawPath(path)

            # Draw preview pictures
            if sample.picture is not None:
                if sample.picture.size().width() < sample.duration / scale:
                    path = QPainterPath()
                    path.addRoundedRect(
                        QRectF(t / scale, 52.5,
                               sample.picture.size().width(), 45), 10, 10)
                    qp.setClipPath(path)
                    qp.drawPixmap(
                        QRect(t / scale, 52.5,
                              sample.picture.size().width(), 45),
                        sample.picture)
                else:
                    path = QPainterPath()
                    path.addRoundedRect(
                        QRectF(t / scale, 52.5, sample.duration / scale, 45),
                        10, 10)
                    qp.setClipPath(path)
                    pic = sample.picture.copy(0, 0, sample.duration / scale,
                                              45)
                    qp.drawPixmap(
                        QRect(t / scale, 52.5, sample.duration / scale, 45),
                        pic)
            t += sample.duration

        # Clear clip path
        path = QPainterPath()
        path.addRect(self.rect().x(),
                     self.rect().y(),
                     self.rect().width(),
                     self.rect().height())
        qp.setClipPath(path)

        # Draw pointer
        qp.setPen(Qt.darkCyan)
        qp.setBrush(QBrush(Qt.darkCyan))

        qp.drawPolygon(poly)
        qp.drawLine(line)
        qp.end()
示例#23
0
 def paintEvent(self, event):
     painter = QPainter(self)
     painter.drawPath(self.path)
示例#24
0
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setRenderHint(QPainter.TextAntialiasing)
        R = 100
        Pi = 3.14159
        deg = Pi * 72 / 180
        points = [
            QPoint(R, 0),
            QPoint(R * math.cos(deg), -R * math.sin(deg)),
            QPoint(R * math.cos(2 * deg), -R * math.sin(2 * deg)),
            QPoint(R * math.cos(3 * deg), -R * math.sin(3 * deg)),
            QPoint(R * math.cos(4 * deg), -R * math.sin(4 * deg))
        ]
        font = painter.font()
        font.setPointSize(12)
        font.setBold(False)
        painter.setFont(font)

        pen = QPen()
        pen.setWidth(2)
        pen.setColor(Qt.blue)
        pen.setStyle(Qt.SolidLine)
        pen.setCapStyle(Qt.FlatCap)
        pen.setJoinStyle(Qt.BevelJoin)
        painter.setPen(pen)

        brush = QBrush()
        brush.setColor(Qt.yellow)
        brush.setStyle(Qt.SolidPattern)
        painter.setBrush(brush)

        starPath = QPainterPath()
        starPath.moveTo(points[0])
        starPath.lineTo(points[2])
        starPath.lineTo(points[4])
        starPath.lineTo(points[1])
        starPath.lineTo(points[3])
        starPath.closeSubpath()

        starPath.addText(points[0], font, "0")
        starPath.addText(points[1], font, "1")
        starPath.addText(points[2], font, "2")
        starPath.addText(points[3], font, "3")
        starPath.addText(points[4], font, "4")

        painter.save()
        painter.translate(100, 120)
        painter.drawPath(starPath)
        painter.drawText(0, 0, "S1")
        painter.restore()

        painter.translate(300, 120)
        painter.scale(0.8, 0.8)
        painter.rotate(90)
        painter.drawPath(starPath)
        painter.drawText(0, 0, "S2")

        painter.resetTransform()
        painter.translate(500, 120)
        painter.rotate(-145)
        painter.drawPath(starPath)
        painter.drawText(0, 0, "S3")
示例#25
0
    def paintEvent(self, event):
        p = QPainter()
        p.begin(self)
        self._normalMap.render(p, event.rect())
        p.setPen(Qt.black)
        p.drawText(
            self.rect(),
            Qt.AlignBottom | Qt.TextWordWrap,
            "Map data CCBYSA 2009 OpenStreetMap.org contributors",
        )
        p.end()

        if self.zoomed:
            dim = min(self.width(), self.height())
            magnifierSize = min(MAX_MAGNIFIER, dim * 2 / 3)
            radius = magnifierSize / 2
            ring = radius - 15
            box = QSize(magnifierSize, magnifierSize)

            # reupdate our mask
            if self.maskPixmap.size() != box:
                self.maskPixmap = QPixmap(box)
                self.maskPixmap.fill(Qt.transparent)
                g = QRadialGradient()
                g.setCenter(radius, radius)
                g.setFocalPoint(radius, radius)
                g.setRadius(radius)
                g.setColorAt(1.0, QColor(255, 255, 255, 0))
                g.setColorAt(0.5, QColor(128, 128, 128, 255))
                mask = QPainter(self.maskPixmap)
                mask.setRenderHint(QPainter.Antialiasing)
                mask.setCompositionMode(QPainter.CompositionMode_Source)
                mask.setBrush(g)
                mask.setPen(Qt.NoPen)
                mask.drawRect(self.maskPixmap.rect())
                mask.setBrush(QColor(Qt.transparent))
                mask.drawEllipse(g.center(), ring, ring)
                mask.end()

            center = self.dragPos - QPoint(0, radius)
            center += QPoint(0, radius / 2)
            corner = center - QPoint(radius, radius)
            xy = center * 2 - QPoint(radius, radius)
            # only set the dimension to the magnified portion
            if self.zoomPixmap.size() != box:
                self.zoomPixmap = QPixmap(box)
                self.zoomPixmap.fill(Qt.lightGray)

            if True:
                p = QPainter(self.zoomPixmap)
                p.translate(-xy)
                self._largeMap.render(p, QRect(xy, box))
                p.end()

            clipPath = QPainterPath()
            clipPath.addEllipse(QPointF(center), ring, ring)
            p = QPainter(self)
            p.setRenderHint(QPainter.Antialiasing)
            p.setClipPath(clipPath)
            p.drawPixmap(corner, self.zoomPixmap)
            p.setClipping(False)
            p.drawPixmap(corner, self.maskPixmap)
            p.setPen(Qt.gray)
            p.drawPath(clipPath)

        if self.invert:
            p = QPainter(self)
            p.setCompositionMode(QPainter.CompositionMode_Difference)
            p.fillRect(event.rect(), Qt.white)
            p.end()
示例#26
0
    def paint(
        self,
        painter: QtGui.QPainter,
        option: QStyleOptionGraphicsItem,
        widget: Optional[QWidget],
    ) -> None:

        # * title
        titlePath = QtGui.QPainterPath()
        titlePath.setFillRule(QtCore.Qt.WindingFill)

        titlePath.addRoundedRect(
            0,
            0,
            self._nodeWidth,
            self._nodeTitleHeight,
            self._nodeEdgeSize,
            self._nodeEdgeSize,
        )

        titlePath.addRect(
            0,
            self._nodeTitleHeight - self._nodeEdgeSize,
            self._nodeEdgeSize,
            self._nodeEdgeSize,
        )

        titlePath.addRect(
            self._nodeWidth - self._nodeEdgeSize,
            self._nodeTitleHeight - self._nodeEdgeSize,
            self._nodeEdgeSize,
            self._nodeEdgeSize,
        )

        painter.setPen(QtCore.Qt.NoPen)
        painter.setBrush(self._nodeTitleBrush)
        painter.drawPath(titlePath.simplified())

        # ? content
        ContentPath = QtGui.QPainterPath()
        ContentPath.setFillRule(QtCore.Qt.WindingFill)
        ContentPath.addRoundedRect(
            0,
            self._nodeTitleHeight,
            self._nodeWidth,
            self._nodeHeight - self._nodeTitleHeight,
            self._nodeEdgeSize,
            self._nodeEdgeSize,
        )
        ContentPath.addRect(
            0, self._nodeTitleHeight, self._nodeEdgeSize, self._nodeEdgeSize
        )
        ContentPath.addRect(
            self._nodeWidth - self._nodeEdgeSize,
            self._nodeTitleHeight,
            self._nodeEdgeSize,
            self._nodeEdgeSize,
        )
        painter.setPen(QtCore.Qt.NoPen)
        painter.setBrush(self._nodeBrushBackground)
        painter.drawPath(ContentPath.simplified())

        # ? outline
        outline = QtGui.QPainterPath()
        outline.addRoundedRect(
            0,
            0,
            self._nodeWidth,
            self._nodeHeight,
            self._nodeEdgeSize,
            self._nodeEdgeSize,
        )

        painter.setPen(
            self._nodePenDefault if not self.isSelected() else self._nodePenSelected
        )
        painter.setBrush(QtCore.Qt.NoBrush)
        painter.drawPath(outline.simplified())
示例#27
0
    def paintEvent(self, event):
        p = QPainter()
        p.begin(self)
        self._normalMap.render(p, event.rect())
        p.setPen(Qt.black)
        p.drawText(self.rect(), Qt.AlignBottom | Qt.TextWordWrap,
                   "Map data CCBYSA 2009 OpenStreetMap.org contributors")
        p.end()

        if self.zoomed:
            dim = min(self.width(), self.height())
            magnifierSize = min(MAX_MAGNIFIER, dim * 2 / 3)
            radius = magnifierSize / 2
            ring = radius - 15
            box = QSize(magnifierSize, magnifierSize)

            # reupdate our mask
            if self.maskPixmap.size() != box:
                self.maskPixmap = QPixmap(box)
                self.maskPixmap.fill(Qt.transparent)
                g = QRadialGradient()
                g.setCenter(radius, radius)
                g.setFocalPoint(radius, radius)
                g.setRadius(radius)
                g.setColorAt(1.0, QColor(255, 255, 255, 0))
                g.setColorAt(0.5, QColor(128, 128, 128, 255))
                mask = QPainter(self.maskPixmap)
                mask.setRenderHint(QPainter.Antialiasing)
                mask.setCompositionMode(QPainter.CompositionMode_Source)
                mask.setBrush(g)
                mask.setPen(Qt.NoPen)
                mask.drawRect(self.maskPixmap.rect())
                mask.setBrush(QColor(Qt.transparent))
                mask.drawEllipse(g.center(), ring, ring)
                mask.end()

            center = self.dragPos - QPoint(0, radius)
            center += QPoint(0, radius / 2)
            corner = center - QPoint(radius, radius)
            xy = center * 2 - QPoint(radius, radius)
            # only set the dimension to the magnified portion
            if self.zoomPixmap.size() != box:
                self.zoomPixmap = QPixmap(box)
                self.zoomPixmap.fill(Qt.lightGray)
    
            if True:
                p = QPainter(self.zoomPixmap)
                p.translate(-xy)
                self._largeMap.render(p, QRect(xy, box))
                p.end()

            clipPath = QPainterPath()
            clipPath.addEllipse(QPointF(center), ring, ring)
            p = QPainter(self)
            p.setRenderHint(QPainter.Antialiasing)
            p.setClipPath(clipPath)
            p.drawPixmap(corner, self.zoomPixmap)
            p.setClipping(False)
            p.drawPixmap(corner, self.maskPixmap)
            p.setPen(Qt.gray)
            p.drawPath(clipPath)

        if self.invert:
            p = QPainter(self)
            p.setCompositionMode(QPainter.CompositionMode_Difference)
            p.fillRect(event.rect(), Qt.white)
            p.end()
示例#28
0
 def paintEvent(self, e):
     qp = QPainter()
     qp.begin(self)
     qp.drawPath(self.path)
     qp.end()
示例#29
0
class Renderer2D:
    def __init__(self, context):
        self.ctx = context
        self.qp = QPainter(self.ctx)

        # Initiate Properties
        #self.fill = QColor(255, 255, 255)
        #self.stroke = QColor(0, 0, 0)
        self.tint = QColor(0, 0, 0)
        self.isFill = True
        self.isStroke = True
        self.isSmooth = True  # Antialiasing

        # Stroke Properties
        #self.strokeWeight = 1
        #self.strokeJoin = Qt.RoundJoin
        #self.strokeCap = Qt.RoundCap

        self.pen = QPen(QColor(0, 0, 0), 1, Qt.SolidLine, Qt.RoundCap,
                        Qt.RoundJoin)
        self.brush = QColor(255, 255, 255)

    def stroke(self, color):
        self.pen.setColor(color)

    def strokeWeight(self, width):
        self.pen.setWidth(width)

    def strokeJoin(self, join):
        if join == "MITER":
            self.pen.setJoinStyle(Qt.MiterJoin)
        elif join == "BEVEL":
            self.pen.setJoinStyle(Qt.BevelJoin)
        elif join == "ROUND":
            self.pen.setJoinStyle(Qt.RoundJoin)
        else:
            print("Invalid Stroke Join")

    def strokeCap(self, cap):
        if cap == "PROJECT":
            self.pen.setJoinStyle(Qt.SquareCap)
        elif cap == "SQUARE":
            self.pen.setJoinStyle(Qt.FlatCap)
        elif cap == "ROUND":
            self.pen.setJoinStyle(Qt.RoundCap)
        else:
            print("Invalid Stroke Cap")

    def fill(self, color):
        self.brush = color

    def background(self, color):
        self.qp.begin(self.ctx)
        self.qp.setPen(QColor(0, 0, 0, 0))
        self.qp.setBrush(color)
        self.qp.drawRect(0, 0,
                         self.ctx.size().width(),
                         self.ctx.size().height())
        self.qp.end()

    def point(self, x, y):
        path = QPainterPath()
        path.moveTo(x, y)
        path.lineTo(x + 0.1, y)

        self.renderPath(path)

    def rect(self, x, y, width, height):
        path = QPainterPath()
        path.moveTo(x, y)
        path.lineTo(x + width, y)
        path.lineTo(x + width, y + height)
        path.lineTo(x, y + height)
        path.lineTo(x, y)

        self.renderPath(path)

    def line(self, x1, y1, x2, y2):
        path = QPainterPath()
        path.moveTo(x1, y1)
        path.lineTo(x2, y2)

        self.renderPath(path)

    def square(self, x, y, s):
        self.rect(x, y, s, s)

    def circle(self, cx, cy, r):
        self.ellipse(cx, cy, r, r)

    def ellipse(self, x, y, w, h):
        kappa = 0.5522847498
        ox = w / 2 * kappa  # control point offset horizontal
        oy = h / 2 * kappa  # control point offset vertical
        xe = x + w  # x-end
        ye = y + h  # y-end
        xm = x + w / 2  # x-middle
        ym = y + h / 2  # y-middle

        path = QPainterPath()
        path.moveTo(x, ym)
        path.cubicTo(x, ym - oy, xm - ox, y, xm, y)
        path.cubicTo(xm + ox, y, xe, ym - oy, xe, ym)
        path.cubicTo(xe, ym + oy, xm + ox, ye, xm, ye)
        path.cubicTo(xm - ox, ye, x, ym + oy, x, ym)

        self.renderPath(path)

    def quad(self, x1, y1, x2, y2, x3, y3, x4, y4):
        path = QPainterPath()
        path.moveTo(x1, y1)
        path.lineTo(x2, y2)
        path.lineTo(x3, y3)
        path.lineTo(x4, y4)
        path.lineTo(x1, y1)

        self.renderPath(path)

    def triangle(self, x1, y1, x2, y2, x3, y3):
        path = QPainterPath()
        path.moveTo(x1, y1)
        path.lineTo(x2, y2)
        path.lineTo(x3, y3)
        path.lineTo(x1, y1)

        self.renderPath(path)

    def renderPath(self, path):
        self.qp.begin(self.ctx)

        if self.isStroke:
            self.qp.setPen(self.pen)
        if self.isFill:
            self.qp.setBrush(self.brush)

        if self.isSmooth:
            self.qp.setRenderHint(QPainter.Antialiasing, True)
            self.qp.setRenderHint(QPainter.HighQualityAntialiasing, True)
            self.qp.setRenderHint(QPainter.SmoothPixmapTransform, True)

        self.qp.drawPath(path)
        self.qp.end()
示例#30
0
    def paintEvent(self, evt):
        x1 = QPoint(0, -70)
        x2 = QPoint(0, -90)
        x3 = QPoint(-90, 0)
        x4 = QPoint(-70, 0)
        extRect = QRectF(-90, -90, 180, 180)
        intRect = QRectF(-70, -70, 140, 140)
        midRect = QRectF(-44, -80, 160, 160)
        unitRect = QRectF(-50, 60, 110, 50)

        speedInt = self.speed
        #speedDec = (self.speed * 10.0) - (speedInt * 10)
        s_SpeedInt = speedInt.__str__()[0:4]

        powerAngle = self.power * 270.0 / 100.0

        dummyPath = QPainterPath()
        dummyPath.moveTo(x1)
        dummyPath.arcMoveTo(intRect, 90 - powerAngle)
        powerPath = QPainterPath()
        powerPath.moveTo(x1)
        powerPath.lineTo(x2)
        powerPath.arcTo(extRect, 90, -1 * powerAngle)
        powerPath.lineTo(dummyPath.currentPosition())
        powerPath.arcTo(intRect, 90 - powerAngle, powerAngle)

        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(self.width() / 2, self.height() / 2)
        side = min(self.width(), self.height())
        painter.scale(side / 200.0, side / 200.0)

        painter.save()
        painter.rotate(-135)

        if self.displayPowerPath:
            externalPath = QPainterPath()
            externalPath.moveTo(x1)
            externalPath.lineTo(x2)
            externalPath.arcTo(extRect, 90, -270)
            externalPath.lineTo(x4)
            externalPath.arcTo(intRect, 180, 270)

            painter.setPen(self.powerPathColor)
            painter.drawPath(externalPath)

        painter.setBrush(self.powerGradient)
        painter.setPen(Qt.NoPen)
        painter.drawPath(powerPath)
        painter.restore()
        painter.save()

        painter.translate(QPointF(0, -50))

        painter.setPen(self.unitTextColor)
        fontFamily = self.font().family()
        unitFont = QFont(fontFamily, 9)
        painter.setFont(unitFont)
        painter.drawText(unitRect, Qt.AlignCenter, "{}".format(self.unit))

        painter.restore()

        painter.setPen(self.unitTextColor)
        fontFamily = self.font().family()
        unitFont = QFont(fontFamily, 12)
        painter.setFont(unitFont)
        painter.drawText(unitRect, Qt.AlignCenter, "{}".format(self.title))

        speedColor = QColor(0, 0, 0)
        speedFont = QFont(fontFamily, 30)
        fm1 = QFontMetrics(speedFont)
        speedWidth = fm1.width(s_SpeedInt)

        #speedDecFont = QFont(fontFamily, 23)
        #fm2 = QFontMetrics(speedDecFont)
        #speedDecWidth = fm2.width(s_SpeedDec)

        leftPos = -1 * speedWidth + 40
        leftDecPos = leftPos + speedWidth
        topPos = 10
        topDecPos = 10
        painter.setPen(self.speedTextColor)
        painter.setFont(speedFont)
        painter.drawText(leftPos, topPos, s_SpeedInt)
示例#31
0
 def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem,
           widget: QWidget):
     painter.setPen(self.pen())
     painter.setBrush(self.brush())
     painter.drawPath(self.path())
示例#32
0
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setPen(Qt.black)
        painter.drawLine(0, 50, 700, 50)  # dividing line

        painter.drawLine(30, 720, 670, 720)  # Ox axis
        painter.drawLine(30, 720, 30, 80)  # Oy axis

        painter.drawLine(670, 720, 665, 715)  # arrow Ox
        painter.drawLine(670, 720, 665, 725)  # arrow Ox
        painter.drawLine(30, 80, 25, 85)  # arrow Oy
        painter.drawLine(30, 80, 35, 85)  # arrow Oy

        if self.points != None:
            for p in self.points:
                pen = QPen()
                pen.setColor(Qt.red)
                pen.setWidth(5)
                painter.setPen(pen)
                painter.drawPoint(30 + p[0], 720 - p[1])

        if self.contour != None:
            pen = QPen()
            pen.setColor(Qt.black)
            painter.setPen(pen)
            for i in range(-1, len(self.contour) - 1):
                painter.drawLine(30 + self.point_dict[self.contour[i]][0],
                                 720 - self.point_dict[self.contour[i]][1],
                                 30 + self.point_dict[self.contour[i + 1]][0],
                                 720 - self.point_dict[self.contour[i + 1]][1])
            path = QPainterPath()
            path.moveTo(30 + self.point_dict[self.contour[-1]][0],
                        720 - self.point_dict[self.contour[-1]][1])
            for i in range(len(self.contour)):
                path.lineTo(30 + self.point_dict[self.contour[i]][0],
                            720 - self.point_dict[self.contour[i]][1])

            path.closeSubpath()

            painter.fillPath(path, QColor(0, 0, 255))

        if self.figure != None:
            for contour in self.figure:
                for i in range(-1, len(contour) - 1):
                    painter.drawLine(30 + contour[i][0], 720 - contour[i][1],
                                     30 + contour[i + 1][0],
                                     720 - contour[i + 1][1])
        if self.triangulation != None:
            for triangle in self.triangulation:
                Ax, Ay, Bx, By, Cx, Cy = triangle
                painter.setPen(Qt.red)
                painter.drawPoint(30 + Ax, 720 - Ay)
                painter.drawPoint(30 + Bx, 720 - By)
                painter.drawPoint(30 + Cx, 720 - Cy)

                painter.setPen(Qt.black)
                painter.drawLine(30 + Ax, 720 - Ay, 30 + Bx, 720 - By)
                painter.drawLine(30 + Bx, 720 - By, 30 + Cx, 720 - Cy)
                painter.drawLine(30 + Cx, 720 - Cy, 30 + Ax, 720 - Ay)

        if self.cells != None:
            pen = QPen()
            max_value = max(self.cells, key=lambda x: x[-1])[-1]
            # print(max_value)
            for cell in self.cells:
                pen.setColor(Qt.blue)
                pen.setWidth(5)
                painter.setPen(pen)
                painter.drawPoint(30 + cell[0], 720 - cell[1])

                value = cell[-1]
                cell = cell[2:-1]
                # pen.setColor(Qt.red)
                # pen.setWidth(1)
                # painter.setPen(pen)

                path = QPainterPath()
                path.moveTo(30 + cell[-2], 720 - cell[-1])
                for i in range(0, len(cell), 2):
                    path.lineTo(30 + cell[i], 720 - cell[i + 1])

                path.closeSubpath()

                painter.fillPath(
                    path,
                    QColor(min(255, int(4 * 255 * value / max_value)), 0,
                           255 - min(255, int(1 * 255 * value / max_value))))

                pen.setColor(Qt.black)
                pen.setWidth(1)
                painter.setPen(pen)
                painter.drawPath(path)
                # for i in range(-2, len(cell) - 2, 2):
                #         painter.drawLine(30 + cell[i], 720 - cell[i + 1], 30 + cell[i + 2], 720 - cell[i + 3])

                pen.setColor(Qt.green)
                pen.setWidth(5)
                painter.setPen(pen)
                for i in range(0, len(cell), 2):
                    painter.drawPoint(30 + cell[i], 720 - cell[i + 1])
示例#33
0
class Renderer2D:
	def __init__(self, context):
		self.ctx = context
		self.qp = QPainter()

		# Initiate Properties
		self.tint = QColor(0, 0, 0)
		self.isSmooth = True # Antialiasing

		# Stroke Properties
		self.pen = QPen(QColor(0, 0, 0), 1, Qt.SolidLine, 
			Qt.RoundCap, Qt.RoundJoin)
		# Fill Properties
		self.brush = QColor(255, 255, 255)

		self.curveTightness = 0

	def stroke(self, color):
		self.pen.setColor(color)

	def strokeWeight(self, width):
		self.pen.setWidth(width)

	def strokeJoin(self, join):
		if join == "MITER":
			self.pen.setJoinStyle(Qt.MiterJoin)
		elif join == "BEVEL":
			self.pen.setJoinStyle(Qt.BevelJoin)
		elif join == "ROUND":
			self.pen.setJoinStyle(Qt.RoundJoin)
		else: 
			print("Invalid Stroke Join")

	def strokeCap(self, cap):
		if cap == "PROJECT":
			self.pen.setJoinStyle(Qt.SquareCap)
		elif cap == "SQUARE":
			self.pen.setJoinStyle(Qt.FlatCap)
		elif cap == "ROUND":
			self.pen.setJoinStyle(Qt.RoundCap)
		else: 
			print("Invalid Stroke Cap")

	def fill(self, color):
		self.brush = color

	def background(self, color):
		#self.qp.begin(self.ctx)
		self.qp.setPen(QColor(0, 0, 0, 0))
		self.qp.setBrush(color)
		self.qp.drawRect(0, 0, self.ctx.size().width(), self.ctx.size().height())
		#self.qp.end()

	def point(self, x, y):
		path = QPainterPath()
		path.moveTo(x, y)
		path.lineTo(x + 0.1, y)

		self.renderPath(path)

	def rect(self, x, y, width, height):
		path = QPainterPath()
		path.moveTo(x, y)
		path.lineTo(x + width, y)
		path.lineTo(x + width, y + height)
		path.lineTo(x, y + height)
		path.lineTo(x, y)

		self.renderPath(path)

	def line(self, x1, y1, x2, y2):
		path = QPainterPath()
		path.moveTo(x1, y1)
		path.lineTo(x2, y2)

		self.renderPath(path)

	def square(self, x, y, s):
		self.rect(x, y, s, s) 

	def circle(self, cx, cy, r):
		self.ellipse(cx, cy, r, r)

	def ellipse(self, x, y, w, h):
		kappa = 0.5522847498
		ox = w/2 * kappa # control point offset horizontal
		oy = h/2 * kappa # control point offset vertical
		xe = x + w # x-end
		ye = y + h # y-end
		xm = x + w/2 # x-middle
		ym = y + h/2 # y-middle

		path = QPainterPath()
		path.moveTo(x, ym)
		path.cubicTo(x, ym - oy, xm - ox, y, xm, y)
		path.cubicTo(xm + ox, y, xe, ym - oy, xe, ym)
		path.cubicTo(xe, ym + oy, xm + ox, ye, xm, ye)
		path.cubicTo(xm - ox, ye, x, ym + oy, x, ym)

		self.renderPath(path)		

	def quad(self, x1, y1, x2, y2, x3, y3, x4, y4):
		path = QPainterPath()
		path.moveTo(x1, y1)
		path.lineTo(x2, y2)
		path.lineTo(x3, y3)
		path.lineTo(x4, y4)
		path.lineTo(x1, y1)

		self.renderPath(path)

	def triangle(self, x1, y1, x2, y2, x3, y3):
		path = QPainterPath()
		path.moveTo(x1, y1)
		path.lineTo(x2, y2)
		path.lineTo(x3, y3)
		path.lineTo(x1, y1)

		self.renderPath(path)

	def endShape(self, mode, vertices, isCurve, isBezier, isQuadratic, isContour, shapeKind):
		if len(vertices) == 0:
			return 
		closeShape = mode == CLOSE

		if closeShape and not isContour:
			vertices.append(vertices[0])

		if isCurve and (shapeKind == POLYGON or shapeKind == None):
			s = 1 - self.curveTightness
			path = QPainterPath()
			path.moveTo(vertices[1][0], vertices[1][1])

			for i in range(1, len(vertices) - 2):
				v = vertices[i]
				b = []
				b.append([v[0], v[1]])
				b.append([
					v[0] + (s * vertices[i + 1][0] - s * vertices[i - 1][0]) / 6,
					v[1] + (s * vertices[i + 1][1] - s * vertices[i - 1][1]) / 6
				])
				b.append([
					vertices[i + 1][0] +
						(s * vertices[i][0] - s * vertices[i + 2][0]) / 6,
					vertices[i + 1][1] + (s * vertices[i][1] - s * vertices[i + 2][1]) / 6
				])
				b.append([vertices[i + 1][0], vertices[i + 1][1]])
				path.cubicTo(
					b[1][0],
					b[1][1],
					b[2][0],
					b[2][1],
					b[3][0],
					b[3][1]
				)

			if closeShape:
				path.lineTo(vertices[i + 1][0], vertices[i + 1][1])
			self.renderPath(path)

		elif isBezier and (shapeKind == POLYGON or shapeKind == None):
			path = QPainterPath()
			path.moveTo(vertices[0][0], vertices[0][1])

			for v in vertices:
				if len(v) == 2:
					path.lineTo(v[0], v[1])
				else:
					path.cubicTo(
						v[0],
						v[1],
						v[2],
						v[3],
						v[4],
						v[5],
					)
			self.renderPath(path)

		elif isQuadratic and (shapeKind == POLYGON or shapeKind == None):
			path = QPainterPath()
			path.moveTo(vertices[0][0], vertices[0][1])
			for v in vertices:
				if len(v) == 2:
					path.lineTo(v[0], v[1])
				else:
					path.quadTo(
						v[0],
						v[1],
						v[2],
						v[3],
					)
			self.renderPath(path)

		else:
			if shapeKind == POINTS:
				for p in vertices:
					self.point(p[0], p[1])
			elif shapeKind == LINES:
				for i in range(0, len(vertices) - 1, 2):
					self.line(vertices[i][0], vertices[i][1], vertices[i + 1][0], vertices[i + 1][1])
			elif shapeKind == TRIANGLES:
				for i in range(0, len(vertices) - 2, 3):
					self.triangle(vertices[i][0], vertices[i][1], 
						vertices[i + 1][0], vertices[i + 1][1],
						vertices[i + 2][0], vertices[i + 2][1])
			elif shapeKind == TRIANGLE_STRIP:
				for i in range(len(vertices) - 2):
					self.triangle(vertices[i][0], vertices[i][1], 
						vertices[i + 1][0], vertices[i + 1][1],
						vertices[i + 2][0], vertices[i + 2][1])
			elif shapeKind == TRIANGLE_FAN:
				for i in range(1, len(vertices) - 1):
					self.triangle(vertices[0][0], vertices[0][1], 
							vertices[i][0], vertices[i][1],
							vertices[i + 1][0], vertices[i + 1][1])
			elif shapeKind == QUADS:
				for i in range(0, len(vertices) - 3, 4):
					self.quad(vertices[i][0], vertices[i][1], 
							vertices[i + 1][0], vertices[i + 1][1],
							vertices[i + 2][0], vertices[i + 2][1],
							vertices[i + 3][0], vertices[i + 3][1])
			elif shapeKind == QUAD_STRIP:
				for i in range(0, len(vertices) - 3, 2):
					self.quad(vertices[i][0], vertices[i][1], 
							vertices[i + 1][0], vertices[i + 1][1],
							vertices[i + 2][0], vertices[i + 2][1],
							vertices[i + 3][0], vertices[i + 3][1])
			else:
				path = QPainterPath()
				path.moveTo(vertices[0][0], vertices[0][1])
				for p in vertices:
					path.lineTo(p[0], p[1])
				self.renderPath(path)

		return

	def renderPath(self, path):
		self.qp.setPen(self.pen)
		self.qp.setBrush(self.brush)

		if self.isSmooth:
			self.qp.setRenderHint(QPainter.Antialiasing, True)
			self.qp.setRenderHint(QPainter.HighQualityAntialiasing, True)
			self.qp.setRenderHint(QPainter.SmoothPixmapTransform, True)

		self.qp.drawPath(path)

	def push(self):
		self.qp.save()

	def pop(self):
		self.qp.restore()

	def applyMatrix(self, a, b, c, d, e, f):
		self.qp.setWorldTransform([
				a, c, e,
				b, d, f,
				0, 0, 1
			])

	def resetMatrix(self):
		self.qp.setWorldTransform(QMatrix([
				[1, 0, 0],
				[0, 1, 0],
				[0, 0, 1]
			]))

	def rotate(self, angle):
		self.qp.rotate(angle)

	def scale(self, *args):
		if len(args) == 1:
			self.qp.scale(args[0], args[0])
		elif len(args) == 2:
			self.qp.scale(args[0], args[1])

	def shearX(self, angle):
		self.qp.shear(angle, 0)

	def shearY(self, angle):
		self.qp.shear(0, angle)

	def translate(self, x, y):
		self.qp.translate(x, y)
示例#34
0
 def paint(self, painter: QPainter, styleOptionGraphicsItem, widget=None):
     # painter.setBrush()
     painter.drawPath(self.path())
示例#35
0
    def overlay_marks(self, img, is_cseed=False, calibration_sheet=False):
        border_color = Qt.white
        base_img = QImage(self.f_size.width(),self.f_size.height(), QImage.Format_ARGB32)
        base_img.fill(border_color)
        img = QImage(img)

        painter = QPainter()
        painter.begin(base_img)

        total_distance_h = round(base_img.width() / self.abstand_v)
        dist_v = round(total_distance_h) / 2
        dist_h = round(total_distance_h) / 2

        img = img.scaledToWidth(base_img.width() - (2 * (total_distance_h)))
        painter.drawImage(total_distance_h,
                          total_distance_h,
                          img)

        #frame around image
        pen = QPen(Qt.black, 2)
        painter.setPen(pen)

        #horz
        painter.drawLine(0, total_distance_h, base_img.width(), total_distance_h)
        painter.drawLine(0, base_img.height()-(total_distance_h), base_img.width(), base_img.height()-(total_distance_h))
        #vert
        painter.drawLine(total_distance_h, 0,  total_distance_h, base_img.height())
        painter.drawLine(base_img.width()-(total_distance_h), 0,  base_img.width()-(total_distance_h), base_img.height())

        #border around img
        border_thick = 6
        Rpath = QPainterPath()
        Rpath.addRect(QRectF((total_distance_h)+(border_thick/2),
                             (total_distance_h)+(border_thick/2),
                             base_img.width()-((total_distance_h)*2)-((border_thick)-1),
                             (base_img.height()-((total_distance_h))*2)-((border_thick)-1)))
        pen = QPen(Qt.black, border_thick)
        pen.setJoinStyle (Qt.MiterJoin)

        painter.setPen(pen)
        painter.drawPath(Rpath)

        Bpath = QPainterPath()
        Bpath.addRect(QRectF((total_distance_h), (total_distance_h),
                             base_img.width()-((total_distance_h)*2), (base_img.height()-((total_distance_h))*2)))
        pen = QPen(Qt.black, 1)
        painter.setPen(pen)
        painter.drawPath(Bpath)

        pen = QPen(Qt.black, 1)
        painter.setPen(pen)
        painter.drawLine(0, base_img.height()/2, total_distance_h, base_img.height()/2)
        painter.drawLine(base_img.width()/2, 0, base_img.width()/2, total_distance_h)

        painter.drawLine(base_img.width()-total_distance_h, base_img.height()/2, base_img.width(), base_img.height()/2)
        painter.drawLine(base_img.width()/2, base_img.height(), base_img.width()/2, base_img.height() - total_distance_h)

        #print code
        f_size = 37
        QFontDatabase.addApplicationFont(os.path.join(os.path.dirname(__file__), 'DejaVuSansMono-Bold.ttf'))
        font = QFont("DejaVu Sans Mono", f_size-11, QFont.Bold)
        font.setPixelSize(35)
        painter.setFont(font)

        if not calibration_sheet:
            if is_cseed: #its a secret
                painter.setPen(QPen(Qt.black, 1, Qt.DashDotDotLine))
                painter.drawLine(0, dist_v, base_img.width(), dist_v)
                painter.drawLine(dist_h, 0,  dist_h, base_img.height())
                painter.drawLine(0, base_img.height()-dist_v, base_img.width(), base_img.height()-(dist_v))
                painter.drawLine(base_img.width()-(dist_h), 0,  base_img.width()-(dist_h), base_img.height())

                painter.drawImage(((total_distance_h))+11, ((total_distance_h))+11,
                                  QImage(':icons/electrumb.png').scaledToWidth(2.1*(total_distance_h), Qt.SmoothTransformation))

                painter.setPen(QPen(Qt.white, border_thick*8))
                painter.drawLine(base_img.width()-((total_distance_h))-(border_thick*8)/2-(border_thick/2)-2,
                                (base_img.height()-((total_distance_h)))-((border_thick*8)/2)-(border_thick/2)-2,
                                base_img.width()-((total_distance_h))-(border_thick*8)/2-(border_thick/2)-2 - 77,
                                (base_img.height()-((total_distance_h)))-((border_thick*8)/2)-(border_thick/2)-2)
                painter.setPen(QColor(0,0,0,255))
                painter.drawText(QRect(0, base_img.height()-107, base_img.width()-total_distance_h - border_thick - 11,
                                       base_img.height()-total_distance_h - border_thick), Qt.AlignRight,
                                 self.versioned_seed.version + '_'+self.versioned_seed.checksum)
                painter.end()

            else: # revealer

                painter.setPen(QPen(border_color, 17))
                painter.drawLine(0, dist_v, base_img.width(), dist_v)
                painter.drawLine(dist_h, 0,  dist_h, base_img.height())
                painter.drawLine(0, base_img.height()-dist_v, base_img.width(), base_img.height()-(dist_v))
                painter.drawLine(base_img.width()-(dist_h), 0,  base_img.width()-(dist_h), base_img.height())

                painter.setPen(QPen(Qt.black, 2))
                painter.drawLine(0, dist_v, base_img.width(), dist_v)
                painter.drawLine(dist_h, 0,  dist_h, base_img.height())
                painter.drawLine(0, base_img.height()-dist_v, base_img.width(), base_img.height()-(dist_v))
                painter.drawLine(base_img.width()-(dist_h), 0,  base_img.width()-(dist_h), base_img.height())
                logo = QImage(':icons/revealer_c.png').scaledToWidth(1.3*(total_distance_h))
                painter.drawImage((total_distance_h)+ (border_thick), ((total_distance_h))+ (border_thick), logo, Qt.SmoothTransformation)

                #frame around logo
                painter.setPen(QPen(Qt.black, border_thick))
                painter.drawLine(total_distance_h+border_thick, total_distance_h+logo.height()+3*(border_thick/2),
                                 total_distance_h+logo.width()+border_thick, total_distance_h+logo.height()+3*(border_thick/2))
                painter.drawLine(logo.width()+total_distance_h+3*(border_thick/2), total_distance_h+(border_thick),
                                 total_distance_h+logo.width()+3*(border_thick/2), total_distance_h+logo.height()+(border_thick))

                #frame around code/qr
                qr_size = 179

                painter.drawLine((base_img.width()-((total_distance_h))-(border_thick/2)-2)-qr_size,
                                (base_img.height()-((total_distance_h)))-((border_thick*8))-(border_thick/2)-2,
                                 (base_img.width()/2+(total_distance_h/2)-border_thick-(border_thick*8)/2)-qr_size,
                                (base_img.height()-((total_distance_h)))-((border_thick*8))-(border_thick/2)-2)

                painter.drawLine((base_img.width()/2+(total_distance_h/2)-border_thick-(border_thick*8)/2)-qr_size,
                                (base_img.height()-((total_distance_h)))-((border_thick*8))-(border_thick/2)-2,
                                 base_img.width()/2 + (total_distance_h/2)-border_thick-(border_thick*8)/2-qr_size,
                                 ((base_img.height()-((total_distance_h)))-(border_thick/2)-2))

                painter.setPen(QPen(Qt.white, border_thick * 8))
                painter.drawLine(
                    base_img.width() - ((total_distance_h)) - (border_thick * 8) / 2 - (border_thick / 2) - 2,
                    (base_img.height() - ((total_distance_h))) - ((border_thick * 8) / 2) - (border_thick / 2) - 2,
                    base_img.width() / 2 + (total_distance_h / 2) - border_thick - qr_size,
                    (base_img.height() - ((total_distance_h))) - ((border_thick * 8) / 2) - (border_thick / 2) - 2)

                painter.setPen(QColor(0,0,0,255))
                painter.drawText(QRect(((base_img.width()/2) +21)-qr_size, base_img.height()-107,
                                       base_img.width()-total_distance_h - border_thick -93,
                                       base_img.height()-total_distance_h - border_thick), Qt.AlignLeft, self.versioned_seed.get_ui_string_version_plus_seed())
                painter.drawText(QRect(0, base_img.height()-107, base_img.width()-total_distance_h - border_thick -3 -qr_size,
                                       base_img.height()-total_distance_h - border_thick), Qt.AlignRight, self.versioned_seed.checksum)

                # draw qr code
                qr_qt = self.paintQR(self.versioned_seed.get_ui_string_version_plus_seed()
                                     + self.versioned_seed.checksum)
                target = QRectF(base_img.width()-65-qr_size,
                                base_img.height()-65-qr_size,
                                qr_size, qr_size )
                painter.drawImage(target, qr_qt)
                painter.setPen(QPen(Qt.black, 4))
                painter.drawLine(base_img.width()-65-qr_size,
                                base_img.height()-65-qr_size,
                                 base_img.width() - 65 - qr_size,
                                (base_img.height() - ((total_distance_h))) - ((border_thick * 8)) - (border_thick / 2) - 4
                                 )
                painter.drawLine(base_img.width()-65-qr_size,
                                base_img.height()-65-qr_size,
                                 base_img.width() - 65,
                                base_img.height()-65-qr_size
                                 )
                painter.end()

        else: # calibration only
            painter.end()
            cal_img = QImage(self.f_size.width() + 100, self.f_size.height() + 100,
                              QImage.Format_ARGB32)
            cal_img.fill(Qt.white)

            cal_painter = QPainter()
            cal_painter.begin(cal_img)
            cal_painter.drawImage(0,0, base_img)

            #black lines in the middle of border top left only
            cal_painter.setPen(QPen(Qt.black, 1, Qt.DashDotDotLine))
            cal_painter.drawLine(0, dist_v, base_img.width(), dist_v)
            cal_painter.drawLine(dist_h, 0,  dist_h, base_img.height())

            pen = QPen(Qt.black, 2, Qt.DashDotDotLine)
            cal_painter.setPen(pen)
            n=15

            cal_painter.setFont(QFont("DejaVu Sans Mono", 21, QFont.Bold))
            for x in range(-n,n):
                #lines on bottom (vertical calibration)
                cal_painter.drawLine((((base_img.width())/(n*2)) *(x))+ (base_img.width()/2)-13,
                                 x+2+base_img.height()-(dist_v),
                                 (((base_img.width())/(n*2)) *(x))+ (base_img.width()/2)+13,
                                 x+2+base_img.height()-(dist_v))

                num_pos = 9
                if x > 9 : num_pos = 17
                if x < 0 : num_pos = 20
                if x < -9: num_pos = 27

                cal_painter.drawText((((base_img.width())/(n*2)) *(x))+ (base_img.width()/2)-num_pos,
                                 50+base_img.height()-(dist_v),
                                  str(x))

                #lines on the right (horizontal calibrations)

                cal_painter.drawLine(x+2+(base_img.width()-(dist_h)),
                                 ((base_img.height()/(2*n)) *(x))+ (base_img.height()/n)+(base_img.height()/2)-13,
                                 x+2+(base_img.width()-(dist_h)),
                                 ((base_img.height()/(2*n)) *(x))+ (base_img.height()/n)+(base_img.height()/2)+13)


                cal_painter.drawText(30+(base_img.width()-(dist_h)),
                                ((base_img.height()/(2*n)) *(x))+ (base_img.height()/2)+13, str(x))

            cal_painter.end()
            base_img = cal_img

        return base_img
示例#36
0
    def redraw(self, painter: QtGui.QPainter, event) -> None:
        # if the button is hidden then there is nothing to draw
        if self._state == ICWidgetState.Hidden:
            return

        # draw the label area
        tmp_width = painter.device().width()
        tmp_height = painter.device().height()

        # define the rectangle to draw the button
        rect = QtCore.QRectF(3, 3, tmp_width-6, tmp_height-6)

        # path to be drawn
        path = QtGui.QPainterPath()
        path.setFillRule(Qt.WindingFill)
        path.addRoundedRect(rect, 10, 10)

        # brush to fill the area
        brush = QtGui.QLinearGradient(rect.topRight(), rect.bottomRight())
        if self._state == ICWidgetState.Transparent:
            brush.setColorAt(0, self.background_color)
            brush.setColorAt(1, self.background_color)
        else:
            brush.setColorAt(0, self._label_color_dark)
            brush.setColorAt(0.5, self._label_color_light)
            brush.setColorAt(1, self._label_color_dark)
        painter.setBrush(brush)

        # define the border pen
        if self._state == ICWidgetState.Transparent:
            pen = QtGui.QPen(self.background_color)
        else:
            pen = QtGui.QPen(self._border_color)
        if self.in_focus:
            pen.setWidth(3)
        else:
            pen.setWidth(1)
        pen.setCapStyle(Qt.RoundCap)
        pen.setJoinStyle(Qt.RoundJoin)
        painter.setPen(pen)

        # draw the rectangle
        painter.drawPath(path)

        # draw the text only if the button is visible
        if self._state in (ICWidgetState.VisibleEnabled, ICWidgetState.VisibleDisabled):
            # draw the name
            fnt = painter.font()
            fnt.setBold(True)
            fnt.setPixelSize(self._name_text_size)
            painter.setFont(fnt)
            pen.setColor(self._name_color)
            painter.setPen(pen)
            rect = QtCore.QRect(10, 10, tmp_width - 20, self._name_text_size + 5)
            painter.drawText(rect, Qt.AlignLeft, str(self._name))

            # draw the value
            fnt.setPixelSize(self._value_text_size)
            painter.setFont(fnt)
            pen.setColor(self._value_color)
            painter.setPen(pen)
            rect = QtCore.QRect(10, tmp_height - (self._value_text_size + 15), tmp_width - 20, self._value_text_size + 5)
            if self.__type == ICTextLabelType.LabelText:
                painter.drawText(rect, Qt.AlignRight, self._value)
            elif self.__type == ICTextLabelType.LabelInteger:
                painter.drawText(rect, Qt.AlignRight, str(self._value))
            else:
                painter.drawText(rect, Qt.AlignRight, self._text_format.format(self._value))
示例#37
0
    def paintEvent(self, _event: QPaintEvent):
        if not self.crop or not self.resolution:
            return

        painter = QPainter(self)

        # Keep a backup of the transform and create a new one
        transform = painter.worldTransform()

        # Set scaling transform
        transform = transform.scale(self.width() / self.resolution.width(),
                                    self.height() / self.resolution.height())

        # Compute the transform to flip the coordinate system on the x axis
        transform_flip = QTransform()
        if self.flip_x:
            transform_flip = transform_flip.translate(self.resolution.width(),
                                                      0.0)
            transform_flip = transform_flip.scale(-1.0, 1.0)

        # Small helper for tuple to QPoint
        def toqp(point):
            return QPoint(point[0], point[1])

        # Starting from here we care about AA
        painter.setRenderHint(QPainter.Antialiasing)

        # Draw all the QR code results
        for res in self.results:
            painter.setWorldTransform(transform_flip * transform, False)

            # Draw lines between all of the QR code points
            pen = QPen(self.qr_outline_pen)
            if res in self.validator_results.result_colors:
                pen.setColor(self.validator_results.result_colors[res])
            painter.setPen(pen)
            num_points = len(res.points)
            for i in range(0, num_points):
                i_n = i + 1

                line_from = toqp(res.points[i])
                line_from += self.crop.topLeft()

                line_to = toqp(
                    res.points[i_n] if i_n < num_points else res.points[0])
                line_to += self.crop.topLeft()

                painter.drawLine(line_from, line_to)

            # Draw the QR code data
            # Note that we reset the world transform to only the scaled transform
            # because otherwise the text could be flipped. We only use transform_flip
            # to map the center point of the result.
            painter.setWorldTransform(transform, False)
            font_metrics = painter.fontMetrics()
            data_metrics = QSize(font_metrics.horizontalAdvance(res.data),
                                 font_metrics.capHeight())

            center_pos = toqp(res.center)
            center_pos += self.crop.topLeft()
            center_pos = transform_flip.map(center_pos)

            text_offset = QPoint(data_metrics.width(), data_metrics.height())
            text_offset = text_offset / 2
            text_offset.setX(-text_offset.x())
            center_pos += text_offset

            padding = self.BG_RECT_PADDING
            bg_rect_pos = center_pos - QPoint(padding,
                                              data_metrics.height() + padding)
            bg_rect_size = data_metrics + (QSize(padding, padding) * 2)
            bg_rect = QRect(bg_rect_pos, bg_rect_size)
            bg_rect_path = QPainterPath()
            radius = self.BG_RECT_CORNER_RADIUS
            bg_rect_path.addRoundedRect(QRectF(bg_rect), radius, radius,
                                        Qt.AbsoluteSize)
            painter.setPen(self.bg_rect_pen)
            painter.fillPath(bg_rect_path, self.bg_rect_fill)
            painter.drawPath(bg_rect_path)

            painter.setPen(self.text_pen)
            painter.drawText(center_pos, res.data)
示例#38
0
 def slideButton(self, painter: QtGui.QPainter):
     if self.width() > 0 and self.height() > 0:
         path = QtGui.QPainterPath()
         path2 = QtGui.QPainterPath()
         
         widthDistance = self.width() - self.height()
         buttonXOffsetModifier = (widthDistance / self.width()) / 10
         alphaModifier = (1 / widthDistance) * buttonXOffsetModifier
         
         if self.isChecked():
             new_alpha = self.buttonForegroundColor.alphaF() + alphaModifier
             
             if new_alpha > 1:
                 new_alpha = 1
             
             self.buttonForegroundColor.setAlphaF(new_alpha)
             self.buttonXOffset += buttonXOffsetModifier
         
         else:
             new_alpha = self.buttonForegroundColor.alphaF() - alphaModifier
             
             if new_alpha < 0:
                 new_alpha = 0
             
             self.buttonForegroundColor.setAlphaF(new_alpha)
             self.buttonXOffset -= buttonXOffsetModifier
         
         if self.buttonXOffset >= (widthDistance + self.ButtonPadding) or self.buttonXOffset <= self.ButtonPadding:
             if self.buttonXOffset > (widthDistance + self.ButtonPadding):
                 self.buttonXOffset = widthDistance + self.ButtonPadding
             
             elif self.buttonXOffset < self.ButtonPadding:
                 self.buttonXOffset = self.ButtonPadding
             
             self.isAnimationScheduled = False
         
         else:
             if not self.isCircular():
                 painter.fillRect(self.rect(), self.buttonBackgroundColor)
                 painter.fillRect(self.rect(), self.buttonForegroundColor)
                 painter.fillRect(QtCore.QRect(
                     self.buttonXOffset,
                     self.ButtonPadding,
                     widthDistance - self.ButtonPadding * 2,
                     self.height() - self.ButtonPadding * 2
                 ), self.buttonColor)
             
             elif self.isCircular():
                 path.addRoundedRect(QtCore.QRectF(self.rect()), self.RoundedRadius, self.height() // 2)
                 painter.fillPath(path, self.buttonBackgroundColor)
                 painter.fillPath(path, self.buttonForegroundColor)
                 
                 path2.addEllipse(QtCore.QRectF(
                     self.buttonXOffset,
                     self.ButtonPadding,
                     self.height() - self.ButtonPadding * 2,
                     self.height() - self.ButtonPadding * 2
                 ))
                 
                 painter.fillPath(path2, self.buttonColor)
                 painter.drawPath(path)
示例#39
0
    def paintEvent(self, event):
        painter = QPainter(self)
        width = self.width()
        height = self.height()

        if DEBUG:
            painter.fillRect(0, 0, width, height, Qt.blue)
        else:
            painter.fillRect(event.rect(), self.plot.canvas_color)

        y_min_scale = self.plot.y_scale.value_min
        y_max_scale = self.plot.y_scale.value_max

        factor_x = width / self.plot.x_diff
        factor_y = (height - CURVE_HEIGHT_COMPENSATION) / max(y_max_scale - y_min_scale, EPSILON)

        if self.plot.x_min != None and self.plot.x_max != None:
            x_min = self.plot.x_min
            x_max = self.plot.x_max

            if self.plot.curve_start == 'left':
                curve_x_offset = 0
            else:
                curve_x_offset = round((self.plot.x_diff - (x_max - x_min)) * factor_x)

            transform = QTransform()

            transform.translate(curve_x_offset, height - CURVE_Y_OFFSET_COMPENSATION)
            transform.scale(factor_x, -factor_y)
            transform.translate(-x_min, -y_min_scale)

            self.plot.partial_update_width = math.ceil(transform.map(QLineF(0, 0, 1.5, 0)).length())
            inverted_event_rect = transform.inverted()[0].mapRect(QRectF(event.rect()))

            painter.save()
            painter.setTransform(transform)

            pen = QPen()
            pen.setCosmetic(True)
            pen.setWidth(0)

            painter.setPen(pen)

            if False and self.plot.curves_visible[0]:
                # Currently unused support for bar graphs.
                # If we need this later on we should add an option to the
                # PlotWidget for it.
                # I tested this for the Sound Pressure Level Bricklet and it works,
                # but it didnt't look good.
                curve_x = self.plot.curves_x[0]
                curve_y = self.plot.curves_y[0]

                t = time.time()
                if self.max_points == None:
                    self.max_points = []
                    for y in curve_y:
                        self.max_points.append((t, y))
                else:
                    for i in range(len(curve_y)):
                        if (curve_y[i] > self.max_points[i][1]) or ((t - self.max_points[i][0]) > 5):
                            self.max_points[i] = (t, curve_y[i])

                for i in range(len(self.plot.curves_x[0])):
                    pen.setColor(self.plot.curve_configs[0].color)
                    painter.setPen(pen)
                    painter.drawLine(QPoint(curve_x[i], 0), QPoint(curve_x[i], curve_y[i]))
                    pen.setColor(Qt.white)
                    painter.setPen(pen)
                    painter.drawLine(QPoint(curve_x[i], curve_y[i]), QPoint(curve_x[i], y_max_scale))
                    pen.setColor(Qt.darkGreen)
                    painter.setPen(pen)
                    painter.drawPoint(QPoint(curve_x[i], self.max_points[i][1]))
            else:
                for c in range(len(self.plot.curves_x)):
                    if not self.plot.curves_visible[c]:
                        continue

                    curve_x = self.plot.curves_x[c]
                    curve_y = self.plot.curves_y[c]
                    curve_jump = self.plot.curves_jump[c]
                    path = QPainterPath()
                    lineTo = path.lineTo
                    moveTo = path.moveTo
                    start = max(min(bisect.bisect_left(curve_x, inverted_event_rect.left()), len(curve_x) - 1) - 1, 0)

                    if start >= len(curve_x):
                        continue

                    moveTo(curve_x[start], curve_y[start])

                    for i in range(start + 1, len(curve_x)):
                        if curve_jump[i]:
                            curve_x_diff_half = (curve_x[i] - curve_x[i - 1]) / 2

                            lineTo(curve_x[i - 1] + curve_x_diff_half, curve_y[i - 1])
                            moveTo(curve_x[i] - curve_x_diff_half, curve_y[i])

                        lineTo(curve_x[i], curve_y[i])

                    pen.setColor(self.plot.curve_configs[c].color)
                    painter.setPen(pen)
                    painter.drawPath(path)

            painter.restore()
示例#40
0
    def createArrowBackground(self, transform):
        scaledRect = transform.mapRect(
            QRect(0, 0, self.logicalSize.width(), self.logicalSize.height()))

        image = QImage(scaledRect.width(), scaledRect.height(),
                       QImage.Format_ARGB32_Premultiplied)
        image.fill(QColor(0, 0, 0, 0).rgba())
        painter = QPainter(image)
        painter.setRenderHint(QPainter.SmoothPixmapTransform)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setPen(Qt.NoPen)

        if Colors.useEightBitPalette:
            painter.setPen(QColor(120, 120, 120))
            if self.pressed:
                painter.setBrush(QColor(60, 60, 60))
            elif self.highlighted:
                painter.setBrush(QColor(100, 100, 100))
            else:
                painter.setBrush(QColor(80, 80, 80))
        else:
            outlinebrush = QLinearGradient(0, 0, 0, scaledRect.height())
            brush = QLinearGradient(0, 0, 0, scaledRect.height())

            brush.setSpread(QLinearGradient.PadSpread)
            highlight = QColor(255, 255, 255, 70)
            shadow = QColor(0, 0, 0, 70)
            sunken = QColor(220, 220, 220, 30)
            normal1 = QColor(200, 170, 160, 50)
            normal2 = QColor(50, 10, 0, 50)

            if self.pressed:
                outlinebrush.setColorAt(0, shadow)
                outlinebrush.setColorAt(1, highlight)
                brush.setColorAt(0, sunken)
                painter.setPen(Qt.NoPen)
            else:
                outlinebrush.setColorAt(1, shadow)
                outlinebrush.setColorAt(0, highlight)
                brush.setColorAt(0, normal1)
                if not self.highlighted:
                    brush.setColorAt(1, normal2)
                painter.setPen(QPen(outlinebrush, 1))

            painter.setBrush(brush)

        painter.drawRect(0, 0, scaledRect.width(), scaledRect.height())

        xOff = scaledRect.width() / 2
        yOff = scaledRect.height() / 2
        sizex = 3.0 * transform.m11()
        sizey = 1.5 * transform.m22()
        if self.type == TextButton.UP:
            sizey *= -1
        path = QPainterPath()
        path.moveTo(xOff, yOff + (5 * sizey))
        path.lineTo(xOff - (4 * sizex), yOff - (3 * sizey))
        path.lineTo(xOff + (4 * sizex), yOff - (3 * sizey))
        path.lineTo(xOff, yOff + (5 * sizey))
        painter.drawPath(path)

        return image
示例#41
0
    def export_new_dataset(self, map, tile_size, step, output_folder):

        # if the dataset folder already had DL subfolder than delete them

        output_folder_training = os.path.join(output_folder, "training")
        output_folder_validation = os.path.join(output_folder, "validation")
        output_folder_test = os.path.join(output_folder, "test")

        if os.path.exists(output_folder_training):
            shutil.rmtree(output_folder_training, ignore_errors=True)
        if os.path.exists(output_folder_validation):
            shutil.rmtree(output_folder_validation, ignore_errors=True)
        if os.path.exists(output_folder_test):
            shutil.rmtree(output_folder_test, ignore_errors=True)

        # create DL folders

        os.mkdir(output_folder_training)
        output_images_training = os.path.join(output_folder_training, "images")
        output_labels_training = os.path.join(output_folder_training, "labels")
        os.mkdir(output_images_training)
        os.mkdir(output_labels_training)

        os.mkdir(output_folder_validation)
        output_images_validation = os.path.join(output_folder_validation,
                                                "images")
        output_labels_validation = os.path.join(output_folder_validation,
                                                "labels")
        os.mkdir(output_images_validation)
        os.mkdir(output_labels_validation)

        os.mkdir(output_folder_test)
        output_images_test = os.path.join(output_folder_test, "images")
        output_labels_test = os.path.join(output_folder_test, "labels")
        os.mkdir(output_images_test)
        os.mkdir(output_labels_test)

        ##### CREATE LABEL IMAGE

        # create a black canvas of the same size of your map
        w = map.width()
        h = map.height()

        labelimg = QImage(w, h, QImage.Format_RGB32)
        labelimg.fill(qRgb(0, 0, 0))

        painter = QPainter(labelimg)

        for i, blob in enumerate(self.seg_blobs):
            if blob.qpath_gitem.isVisible():
                if blob.qpath_gitem.isVisible():
                    if blob.class_name == "Empty":
                        rgb = qRgb(255, 255, 255)
                    else:
                        class_color = self.labels_info[blob.class_name]
                        rgb = qRgb(class_color[0], class_color[1],
                                   class_color[2])

                    painter.setBrush(QBrush(QColor(rgb)))
                    painter.drawPath(blob.qpath_gitem.path())

        painter.end()

        ##### TILING

        h1 = h * 0.65
        h2 = h * 0.85

        # tiles within the height [0..h1] are used for the training
        # tiles within the height [h1..h2] are used for the validation
        # the other tiles are used for the test

        tile_cols = int((w + tile_size) / step)
        tile_rows = int((h + tile_size) / step)

        deltaW = int(tile_size / 2) + 1
        deltaH = int(tile_size / 2) + 1

        for row in range(tile_rows):
            for col in range(tile_cols):

                top = row * step - deltaH
                left = col * step - deltaW
                cropimg = utils.cropQImage(map,
                                           [top, left, tile_size, tile_size])
                croplabel = utils.cropQImage(labelimg,
                                             [top, left, tile_size, tile_size])

                filenameRGB = ""

                if top + tile_size < h1 - step:

                    filenameRGB = os.path.join(
                        output_images_training,
                        "tile_" + str.format("{0:02d}", (row)) + "_" +
                        str.format("{0:02d}", (col)) + ".png")
                    filenameLabel = os.path.join(
                        output_labels_training,
                        "tile_" + str.format("{0:02d}", (row)) + "_" +
                        str.format("{0:02d}", (col)) + ".png")

                elif top > h2 + step:

                    filenameRGB = os.path.join(
                        output_images_test,
                        "tile_" + str.format("{0:02d}", (row)) + "_" +
                        str.format("{0:02d}", (col)) + ".png")
                    filenameLabel = os.path.join(
                        output_labels_test,
                        "tile_" + str.format("{0:02d}", (row)) + "_" +
                        str.format("{0:02d}", (col)) + ".png")

                elif top + tile_size >= h1 + step and top <= h2 - step:

                    filenameRGB = os.path.join(
                        output_images_validation,
                        "tile_" + str.format("{0:02d}", (row)) + "_" +
                        str.format("{0:02d}", (col)) + ".png")
                    filenameLabel = os.path.join(
                        output_labels_validation,
                        "tile_" + str.format("{0:02d}", (row)) + "_" +
                        str.format("{0:02d}", (col)) + ".png")

                print(filenameRGB)
                print(filenameLabel)

                if filenameRGB != "":
                    cropimg.save(filenameRGB)
                    croplabel.save(filenameLabel)
示例#42
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setupUi(self)

        points = [(0, 0), (-6.6572836, 4.361927), (-9.2177166, 7.340494),
                  (-2.2137959, 2.5753221), (-4.66601534, 6.1499951),
                  (-4.81185534, 9.5429151), (-0.070593, 1.642318),
                  (1.35985124, 3.843193), (2.70403794, 4.203864),
                  (3.9058194, 1.048006), (7.699405, -2.258071),
                  (11.636839, -2.220768), (4.653883, 0.04409),
                  (8.669976, 4.329893), (13.502289, 2.931417),
                  (7.08685, -2.050941), (17.480776, -9.315182),
                  (14.745917, -16.1672141), (-0.308121, -0.771981),
                  (-2.309601, -0.355324), (-2.309601, -0.355324)]
        points = [QPointF(*p) * 10 for p in points]
        path = QPainterPath()
        ref_p = QPointF(14.1681, 0.2321) * 10
        path.moveTo(ref_p)
        for i in range(0, len(points) - 2, 3):
            ep = points[i + 2] + ref_p
            c1 = points[i] + ref_p
            c2 = points[i + 1] + ref_p
            path.cubicTo(c1, c2, ep)
            ref_p = ep

        rect = path.boundingRect().adjusted(-5, -5, 5, 5)

        pen_styles = {
            k: getattr(Qt, k)
            for k in dir(Qt) if isinstance(getattr(Qt, k), Qt.PenStyle)
        }
        for name, style in sorted(pen_styles.items(), key=lambda x: x[1]):
            if "PenStyle" in name or "Custom" in name or "NoPen" in name:
                continue
            item = QListWidgetItem(name)
            item.setData(PenParametersDialog.PenStyleRole, style)
            pixmap = QPixmap(int(rect.width()), int(rect.height()))
            pixmap.fill(Qt.transparent)
            painter = QPainter()
            painter.begin(pixmap)
            painter.setPen(QPen(Qt.darkGreen, 10, style))
            painter.drawPath(path)
            painter.end()
            item.setIcon(QIcon(pixmap))
            self.lstPenStyles.addItem(item)

        colors = {
            k: getattr(Qt, k)
            for k in dir(Qt) if isinstance(getattr(Qt, k), Qt.GlobalColor)
        }
        for name, color in sorted(colors.items(), key=lambda x: x[1]):
            if "color" in name or name == "transparent":
                continue
            item = QListWidgetItem(name)
            item.setData(PenParametersDialog.ColorRole, color)
            pixmap = QPixmap(100, 25)
            painter = QPainter()
            painter.begin(pixmap)
            painter.setBrush(color)
            painter.drawRect(pixmap.rect())
            painter.end()
            item.setIcon(QIcon(pixmap))
            self.lstPenColors.addItem(item)
示例#43
0
    def overlay_marks(self, img, is_cseed=False, calibration_sheet=False):
        border_color = Qt.white
        base_img = QImage(self.f_size.width(),self.f_size.height(), QImage.Format_ARGB32)
        base_img.fill(border_color)
        img = QImage(img)

        painter = QPainter()
        painter.begin(base_img)

        total_distance_h = round(base_img.width() / self.abstand_v)
        dist_v = round(total_distance_h) / 2
        dist_h = round(total_distance_h) / 2

        img = img.scaledToWidth(base_img.width() - (2 * (total_distance_h)))
        painter.drawImage(total_distance_h,
                          total_distance_h,
                          img)

        #frame around image
        pen = QPen(Qt.black, 2)
        painter.setPen(pen)

        #horz
        painter.drawLine(0, total_distance_h, base_img.width(), total_distance_h)
        painter.drawLine(0, base_img.height()-(total_distance_h), base_img.width(), base_img.height()-(total_distance_h))
        #vert
        painter.drawLine(total_distance_h, 0,  total_distance_h, base_img.height())
        painter.drawLine(base_img.width()-(total_distance_h), 0,  base_img.width()-(total_distance_h), base_img.height())

        #border around img
        border_thick = 6
        Rpath = QPainterPath()
        Rpath.addRect(QRectF((total_distance_h)+(border_thick/2),
                             (total_distance_h)+(border_thick/2),
                             base_img.width()-((total_distance_h)*2)-((border_thick)-1),
                             (base_img.height()-((total_distance_h))*2)-((border_thick)-1)))
        pen = QPen(Qt.black, border_thick)
        pen.setJoinStyle (Qt.MiterJoin)

        painter.setPen(pen)
        painter.drawPath(Rpath)

        Bpath = QPainterPath()
        Bpath.addRect(QRectF((total_distance_h), (total_distance_h),
                             base_img.width()-((total_distance_h)*2), (base_img.height()-((total_distance_h))*2)))
        pen = QPen(Qt.black, 1)
        painter.setPen(pen)
        painter.drawPath(Bpath)

        pen = QPen(Qt.black, 1)
        painter.setPen(pen)
        painter.drawLine(0, base_img.height()/2, total_distance_h, base_img.height()/2)
        painter.drawLine(base_img.width()/2, 0, base_img.width()/2, total_distance_h)

        painter.drawLine(base_img.width()-total_distance_h, base_img.height()/2, base_img.width(), base_img.height()/2)
        painter.drawLine(base_img.width()/2, base_img.height(), base_img.width()/2, base_img.height() - total_distance_h)

        #print code
        f_size = 37
        QFontDatabase.addApplicationFont(os.path.join(os.path.dirname(__file__), 'DejaVuSansMono-Bold.ttf'))
        font = QFont("DejaVu Sans Mono", f_size-11, QFont.Bold)
        font.setPixelSize(35)
        painter.setFont(font)

        if not calibration_sheet:
            if is_cseed: #its a secret
                painter.setPen(QPen(Qt.black, 1, Qt.DashDotDotLine))
                painter.drawLine(0, dist_v, base_img.width(), dist_v)
                painter.drawLine(dist_h, 0,  dist_h, base_img.height())
                painter.drawLine(0, base_img.height()-dist_v, base_img.width(), base_img.height()-(dist_v))
                painter.drawLine(base_img.width()-(dist_h), 0,  base_img.width()-(dist_h), base_img.height())

                painter.drawImage(((total_distance_h))+11, ((total_distance_h))+11,
                                  QImage(icon_path('electrumb.png')).scaledToWidth(2.1*(total_distance_h), Qt.SmoothTransformation))

                painter.setPen(QPen(Qt.white, border_thick*8))
                painter.drawLine(base_img.width()-((total_distance_h))-(border_thick*8)/2-(border_thick/2)-2,
                                (base_img.height()-((total_distance_h)))-((border_thick*8)/2)-(border_thick/2)-2,
                                base_img.width()-((total_distance_h))-(border_thick*8)/2-(border_thick/2)-2 - 77,
                                (base_img.height()-((total_distance_h)))-((border_thick*8)/2)-(border_thick/2)-2)
                painter.setPen(QColor(0,0,0,255))
                painter.drawText(QRect(0, base_img.height()-107, base_img.width()-total_distance_h - border_thick - 11,
                                       base_img.height()-total_distance_h - border_thick), Qt.AlignRight,
                                 self.versioned_seed.version + '_'+self.versioned_seed.checksum)
                painter.end()

            else: # revealer

                painter.setPen(QPen(border_color, 17))
                painter.drawLine(0, dist_v, base_img.width(), dist_v)
                painter.drawLine(dist_h, 0,  dist_h, base_img.height())
                painter.drawLine(0, base_img.height()-dist_v, base_img.width(), base_img.height()-(dist_v))
                painter.drawLine(base_img.width()-(dist_h), 0,  base_img.width()-(dist_h), base_img.height())

                painter.setPen(QPen(Qt.black, 2))
                painter.drawLine(0, dist_v, base_img.width(), dist_v)
                painter.drawLine(dist_h, 0,  dist_h, base_img.height())
                painter.drawLine(0, base_img.height()-dist_v, base_img.width(), base_img.height()-(dist_v))
                painter.drawLine(base_img.width()-(dist_h), 0,  base_img.width()-(dist_h), base_img.height())
                logo = QImage(icon_path('revealer_c.png')).scaledToWidth(1.3*(total_distance_h))
                painter.drawImage((total_distance_h)+ (border_thick), ((total_distance_h))+ (border_thick), logo, Qt.SmoothTransformation)

                #frame around logo
                painter.setPen(QPen(Qt.black, border_thick))
                painter.drawLine(total_distance_h+border_thick, total_distance_h+logo.height()+3*(border_thick/2),
                                 total_distance_h+logo.width()+border_thick, total_distance_h+logo.height()+3*(border_thick/2))
                painter.drawLine(logo.width()+total_distance_h+3*(border_thick/2), total_distance_h+(border_thick),
                                 total_distance_h+logo.width()+3*(border_thick/2), total_distance_h+logo.height()+(border_thick))

                #frame around code/qr
                qr_size = 179

                painter.drawLine((base_img.width()-((total_distance_h))-(border_thick/2)-2)-qr_size,
                                (base_img.height()-((total_distance_h)))-((border_thick*8))-(border_thick/2)-2,
                                 (base_img.width()/2+(total_distance_h/2)-border_thick-(border_thick*8)/2)-qr_size,
                                (base_img.height()-((total_distance_h)))-((border_thick*8))-(border_thick/2)-2)

                painter.drawLine((base_img.width()/2+(total_distance_h/2)-border_thick-(border_thick*8)/2)-qr_size,
                                (base_img.height()-((total_distance_h)))-((border_thick*8))-(border_thick/2)-2,
                                 base_img.width()/2 + (total_distance_h/2)-border_thick-(border_thick*8)/2-qr_size,
                                 ((base_img.height()-((total_distance_h)))-(border_thick/2)-2))

                painter.setPen(QPen(Qt.white, border_thick * 8))
                painter.drawLine(
                    base_img.width() - ((total_distance_h)) - (border_thick * 8) / 2 - (border_thick / 2) - 2,
                    (base_img.height() - ((total_distance_h))) - ((border_thick * 8) / 2) - (border_thick / 2) - 2,
                    base_img.width() / 2 + (total_distance_h / 2) - border_thick - qr_size,
                    (base_img.height() - ((total_distance_h))) - ((border_thick * 8) / 2) - (border_thick / 2) - 2)

                painter.setPen(QColor(0,0,0,255))
                painter.drawText(QRect(((base_img.width()/2) +21)-qr_size, base_img.height()-107,
                                       base_img.width()-total_distance_h - border_thick -93,
                                       base_img.height()-total_distance_h - border_thick), Qt.AlignLeft, self.versioned_seed.get_ui_string_version_plus_seed())
                painter.drawText(QRect(0, base_img.height()-107, base_img.width()-total_distance_h - border_thick -3 -qr_size,
                                       base_img.height()-total_distance_h - border_thick), Qt.AlignRight, self.versioned_seed.checksum)

                # draw qr code
                qr_qt = self.paintQR(self.versioned_seed.get_ui_string_version_plus_seed()
                                     + self.versioned_seed.checksum)
                target = QRectF(base_img.width()-65-qr_size,
                                base_img.height()-65-qr_size,
                                qr_size, qr_size )
                painter.drawImage(target, qr_qt)
                painter.setPen(QPen(Qt.black, 4))
                painter.drawLine(base_img.width()-65-qr_size,
                                base_img.height()-65-qr_size,
                                 base_img.width() - 65 - qr_size,
                                (base_img.height() - ((total_distance_h))) - ((border_thick * 8)) - (border_thick / 2) - 4
                                 )
                painter.drawLine(base_img.width()-65-qr_size,
                                base_img.height()-65-qr_size,
                                 base_img.width() - 65,
                                base_img.height()-65-qr_size
                                 )
                painter.end()

        else: # calibration only
            painter.end()
            cal_img = QImage(self.f_size.width() + 100, self.f_size.height() + 100,
                              QImage.Format_ARGB32)
            cal_img.fill(Qt.white)

            cal_painter = QPainter()
            cal_painter.begin(cal_img)
            cal_painter.drawImage(0,0, base_img)

            #black lines in the middle of border top left only
            cal_painter.setPen(QPen(Qt.black, 1, Qt.DashDotDotLine))
            cal_painter.drawLine(0, dist_v, base_img.width(), dist_v)
            cal_painter.drawLine(dist_h, 0,  dist_h, base_img.height())

            pen = QPen(Qt.black, 2, Qt.DashDotDotLine)
            cal_painter.setPen(pen)
            n=15

            cal_painter.setFont(QFont("DejaVu Sans Mono", 21, QFont.Bold))
            for x in range(-n,n):
                #lines on bottom (vertical calibration)
                cal_painter.drawLine((((base_img.width())/(n*2)) *(x))+ (base_img.width()/2)-13,
                                 x+2+base_img.height()-(dist_v),
                                 (((base_img.width())/(n*2)) *(x))+ (base_img.width()/2)+13,
                                 x+2+base_img.height()-(dist_v))

                num_pos = 9
                if x > 9 : num_pos = 17
                if x < 0 : num_pos = 20
                if x < -9: num_pos = 27

                cal_painter.drawText((((base_img.width())/(n*2)) *(x))+ (base_img.width()/2)-num_pos,
                                 50+base_img.height()-(dist_v),
                                  str(x))

                #lines on the right (horizontal calibrations)

                cal_painter.drawLine(x+2+(base_img.width()-(dist_h)),
                                 ((base_img.height()/(2*n)) *(x))+ (base_img.height()/n)+(base_img.height()/2)-13,
                                 x+2+(base_img.width()-(dist_h)),
                                 ((base_img.height()/(2*n)) *(x))+ (base_img.height()/n)+(base_img.height()/2)+13)


                cal_painter.drawText(30+(base_img.width()-(dist_h)),
                                ((base_img.height()/(2*n)) *(x))+ (base_img.height()/2)+13, str(x))

            cal_painter.end()
            base_img = cal_img

        return base_img
示例#44
0
   def paintEvent(self,event):  #在窗口上绘图
      painter=QPainter(self)
      painter.setRenderHint(QPainter.Antialiasing)
      painter.setRenderHint(QPainter.TextAntialiasing)


##生成五角星的5个顶点的,假设原点在五角星中心
      R=100.0        #半径
      Pi=3.14159     #常数
      deg=Pi*72.0/180   
      points=[QPoint(R,0),
              QPoint(R*math.cos(deg),    -R*math.sin(deg)),
              QPoint(R*math.cos(2*deg),  -R*math.sin(2*deg)),
              QPoint(R*math.cos(3*deg),  -R*math.sin(3*deg)),
              QPoint(R*math.cos(4*deg),  -R*math.sin(4*deg)) ]   #元组数据

      font=painter.font()
      font.setPointSize(14)
      font.setBold(False)
      painter.setFont(font)

   #设置画笔
      pen=QPen()
      pen.setWidth(2)   #线宽
      pen.setColor(Qt.blue)      #划线颜色
      pen.setStyle(Qt.SolidLine) #线的类型,实线、虚线等
      pen.setCapStyle(Qt.FlatCap)      #线端点样式
      pen.setJoinStyle(Qt.BevelJoin)   #线的连接点样式
      painter.setPen(pen)
      
##设置画刷
      brush=QBrush()
      brush.setColor(Qt.yellow)        #画刷颜色
      brush.setStyle(Qt.SolidPattern)  #填充样式
      painter.setBrush(brush)

##设计绘制五角星的PainterPath,以便重复使用
      starPath=QPainterPath()
      starPath.moveTo(points[0])
      starPath.lineTo(points[2])
      starPath.lineTo(points[4])
      starPath.lineTo(points[1])
      starPath.lineTo(points[3])
      starPath.closeSubpath()    #闭合路径,最后一个点与第一个点相连

      
      starPath.addText(points[0],font,"0") #显示端点编号
      starPath.addText(points[1],font,"1")
      starPath.addText(points[2],font,"2")
      starPath.addText(points[3],font,"3")
      starPath.addText(points[4],font,"4")

##绘图
      painter.save()    #保存坐标状态
      painter.translate(100,120)
      painter.drawPath(starPath)    #画星星
      painter.drawText(0,0,"S1")
      painter.restore()    #恢复坐标状态

      painter.translate(300,120)    #平移
      painter.scale(0.8,0.8)        #缩放
      painter.rotate(90)         #顺时针旋转
      painter.drawPath(starPath) #画星星
      painter.drawText(0,0,"S2")

      painter.resetTransform()      #复位所有坐标变换
      painter.translate(500,120)    #平移
      painter.rotate(-145)          #逆时针旋转
      painter.drawPath(starPath)    #画星星
      painter.drawText(0,0,"S3")    
示例#45
0
    def paintEvent(self, event):
        super(WaterWidget, self).paintEvent(event)
        if self.minimum >= self.maximum:
            return
        if not self._updateTimer.isActive():
            return

        # 正弦曲线公式 y = A * sin(ωx + φ) + k
        # 当前值所占百分比
        percent = 1 - (self._value - self.minimum) / \
                  (self.maximum - self.minimum)
        # w表示周期,6为人为定义
        w = 6 * self.waterDensity * math.pi / self.width()
        # A振幅 高度百分比,1/26为人为定义
        A = self.height() * self.waterHeight * 1 / 26
        # k 高度百分比
        k = self.height() * percent

        # 波浪1
        waterPath1 = QPainterPath()
        waterPath1.moveTo(0, self.height())  # 起点在左下角
        # 波浪2
        waterPath2 = QPainterPath()
        waterPath2.moveTo(0, self.height())  # 起点在左下角

        # 偏移
        self._offset += 0.6
        if self._offset > self.width() / 2:
            self._offset = 0

        for i in range(self.width() + 1):
            # 从x轴开始计算y轴点
            y = A * math.sin(w * i + self._offset) + k
            waterPath1.lineTo(i, y)

            # 相对第一条需要进行错位
            y = A * math.sin(w * i + self._offset + self.width() / 2 * A) + k
            waterPath2.lineTo(i, y)

        # 封闭两条波浪,形成一个 U形 上面加波浪的封闭区间
        waterPath1.lineTo(self.width(), self.height())
        waterPath1.lineTo(0, self.height())
        waterPath2.lineTo(self.width(), self.height())
        waterPath2.lineTo(0, self.height())

        # 开始画路径
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
        # 设置没有画笔
        painter.setPen(Qt.NoPen)

        # 波浪1
        painter.save()
        painter.setBrush(self._waterBgColor)
        painter.drawPath(waterPath1)
        painter.restore()

        # 波浪2
        painter.save()
        painter.setBrush(self._waterFgColor)
        painter.drawPath(waterPath2)
        painter.restore()
示例#46
0
    def paintEvent(self, event):
        painter = QPainter(self)
        metrics = self.fontMetrics()

        # tabs
        self._closeRects = {}
        self._tabsRects = {}
        painter.save()
        currentTab = self.currentTab()
        tabFillColor = QColor(240, 240, 240)
        hoverFillColor = QColor(253, 253, 255)
        textHeight = metrics.lineSpacing()
        left = 0
        h = textHeight + topPadding * 2
        for index, name in enumerate(self.tabs()):
            isHeroFirstTab = not index and self._heroFirstTab
            isClosable = not isHeroFirstTab
            textWidth = self._textWidth
            if not index:
                textWidth += self._firstOffset
            w = sidePadding * 2 + textWidth
            if isClosable:
                w += crossMargin + crossSize
            self._tabsRects[index] = (left, 0, w, h)

            # background
            textColor = QColor(72, 72, 72)
            if index == currentTab:
                fillColor = tabFillColor
            elif index == self._hoverTab:
                fillColor = hoverFillColor
            else:
                fillColor = None
            if fillColor is not None:
                painter.fillRect(0, 0, w, h, fillColor)
            # text
            painter.save()
            painter.translate(sidePadding, metrics.ascent() + topPadding)
            painter.setPen(textColor)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.drawText(
                0, 0, metrics.elidedText(name, Qt.ElideRight, textWidth))
            # cross
            if isClosable:
                # 3px padding for click rect
                self._closeRects[index] = (left + textWidth + 2 * sidePadding -
                                           3, metrics.ascent() + topPadding -
                                           crossSize - 3, crossSize + 6,
                                           crossSize + 6)
                if index == self._hoverClose:
                    color = QColor(254, 28, 28)
                else:
                    color = QColor(78, 78, 78)
                painter.setPen(color)
                pen = painter.pen()
                pen.setWidthF(1.5)
                painter.setPen(pen)
                painter.translate(textWidth + sidePadding, -crossSize)
                painter.setClipRect(0, 0, crossSize, crossSize)
                painter.scale(crossSize / 10, crossSize / 10)
                painter.drawPath(cross)
            painter.restore()
            # shift for the next tab
            shift = textWidth + 2 * sidePadding + spacing
            if isClosable:
                shift += crossMargin + crossSize
            painter.translate(shift, 0)
            left += shift
        painter.restore()
示例#47
0
    def paintEvent(self,event):
        global monster_data
        global dmg
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.drawPixmap(event.rect(),self.pixmap)

        if self.card is not None and self.card.ID is not 0:
            card = self.card
            # Draw card level at the bottom centered
            pen = QPen()
            if np.floor(card.lv) == monster_data[card.ID]['max_level']:
                lvstr = 'Lv.Max'
                brush = QBrush(QColor(252,232,131))
            else:
                lvstr = 'Lv.%d' % np.floor(card.lv)
                brush = QBrush(Qt.white)

            path = QPainterPath()
            pen.setWidth(0);
            pen.setBrush(Qt.black)

            font = QFont()
            font.setPointSize(11)
            font.setWeight(QFont.Black)
            
            path.addText(event.rect().x(),event.rect().y()+48,font,lvstr)

            rect = path.boundingRect()
            target = (event.rect().x()+event.rect().width())/2

            # center the rect in event.rect()
            path.translate(target-rect.center().x(), 0)

            painter.setPen(pen)
            painter.setBrush(QBrush(Qt.black))
            painter.drawPath(path.translated(.5,.5))

            painter.setPen(pen)
            painter.setBrush(brush)

            painter.drawPath(path)

            # Draw +eggs at the top right
            eggs = card.plus_atk+card.plus_hp+card.plus_rcv
            if eggs > 0:
                eggstr = '+%d' % eggs
                pen.setBrush(Qt.yellow)
                brush = QBrush(Qt.yellow)

                path = QPainterPath()
                pen.setWidth(0)
                pen.setBrush(Qt.black)
                font = QFont()
                font.setPointSize(11)
                font.setWeight(QFont.Black)
                path.addText(event.rect().x(),event.rect().y()+12,font,eggstr)

                path.translate(50-path.boundingRect().right()-3,0)
                #painter.setFont(font)
                painter.setPen(pen)
                painter.setBrush(QBrush(Qt.black))
                painter.drawPath(path.translated(.5,.5))

                painter.setPen(pen)
                painter.setBrush(brush)
                painter.drawPath(path)
                #painter.drawText(event.rect().adjusted(0,0,0,0),Qt.AlignRight, eggstr)

            # Draw awakenings at the top left in a green circle
            if card.current_awakening > 0:
                path = QPainterPath()
                rect = QRectF(event.rect()).adjusted(4,4,-36,-36)
                path.addEllipse(rect)
                painter.setBrush(QBrush(QColor(34,139,34)))
                pen.setBrush(Qt.white)
                pen.setWidth(1)
                painter.setPen(pen)
                painter.drawPath(path)

                path = QPainterPath()
                font.setPointSize(9)
                awkstr = ('%d' % card.current_awakening if
                        card.current_awakening < card.max_awakening else
                        '★')
                path.addText(rect.x(),rect.bottom(),font,awkstr)
                
                br = path.boundingRect()
                path.translate(rect.center().x()-br.center().x(),
                        rect.center().y()-br.center().y())

                pen.setBrush(QColor(0,0,0,0))
                pen.setWidth(0)
                painter.setPen(pen)
                painter.setBrush(QBrush(Qt.yellow))
                painter.drawPath(path)

            # Draw main attack damage
            #print(self.main_attack)
            if self.main_attack > 0:
                matkstr = '%d' % self.main_attack
                painter.setBrush(QBrush(COLORS[self.card.element[0]]))
                path = QPainterPath()
                font = QFont()
                font.setFamily('Helvetica')
                font.setWeight(QFont.Black)
                #font.setStretch(25)
                font.setPointSize(13)
                path.addText(rect.x(),rect.bottom(),font,matkstr)

                rect = QRectF(event.rect())
                br = path.boundingRect()
                path.translate(rect.center().x()-br.center().x(),
                        rect.center().y()-br.bottom()-1)

                # 
                pen.setBrush(Qt.black)
                pen.setWidthF(.75)
                painter.setPen(pen)
                painter.drawPath(path)

            # Draw sub attack damage
            #print(self.main_attack)
            if self.sub_attack > 0:
                satkstr = '%d' % self.sub_attack
                painter.setBrush(QBrush(COLORS[self.card.element[1]]))
                path = QPainterPath()
                font = QFont()
                font.setFamily('Helvetica')
                font.setWeight(QFont.Black)
                #font.setStretch(25)
                font.setPointSize(12)
                path.addText(rect.x(),rect.bottom(),font,satkstr)

                rect = QRectF(event.rect())
                br = path.boundingRect()
                path.translate(rect.center().x()-br.center().x(),
                        rect.center().y()-br.top()+1)

                # 
                pen.setBrush(Qt.black)
                pen.setWidthF(.75)
                painter.setPen(pen)
                painter.drawPath(path)
示例#48
0
    def paintEvent(self, event):
        qp = QPainter()
        qp.begin(self)
        qp.setRenderHint(QPainter.Antialiasing)

        # for regular keycaps
        regular_pen = qp.pen()
        regular_pen.setColor(QApplication.palette().color(QPalette.ButtonText))
        qp.setPen(regular_pen)

        regular_brush = QBrush()
        regular_brush.setColor(QApplication.palette().color(QPalette.Button))
        regular_brush.setStyle(Qt.SolidPattern)
        qp.setBrush(regular_brush)

        # for currently selected keycap
        active_pen = qp.pen()
        active_pen.setColor(QApplication.palette().color(QPalette.HighlightedText))

        active_brush = QBrush()
        active_brush.setColor(QApplication.palette().color(QPalette.Highlight))
        active_brush.setStyle(Qt.SolidPattern)

        mask_font = qp.font()
        mask_font.setPointSize(mask_font.pointSize() * 0.8)

        for idx, key in enumerate(self.widgets):
            qp.save()

            qp.scale(self.scale, self.scale)
            qp.translate(key.shift_x, key.shift_y)
            qp.translate(key.rotation_x, key.rotation_y)
            qp.rotate(key.rotation_angle)
            qp.translate(-key.rotation_x, -key.rotation_y)

            active = key.active or (self.active_key == key and not self.active_mask)
            if active:
                qp.setPen(active_pen)
                qp.setBrush(active_brush)

            # draw the keycap
            qp.drawPath(key.draw_path)
            qp.strokePath(key.draw_path2, regular_pen)

            # if this is a mask key, draw the inner key
            if key.masked:
                qp.setFont(mask_font)
                qp.save()
                if key.color is not None and not active:
                    qp.setPen(key.color)
                qp.drawText(key.nonmask_rect, Qt.AlignCenter, key.text)
                qp.restore()

                if self.active_key == key and self.active_mask:
                    qp.setPen(active_pen)
                    qp.setBrush(active_brush)

                qp.drawRect(key.mask_rect)
                if key.color is not None and not active:
                    qp.setPen(key.color)
                qp.drawText(key.mask_rect, Qt.AlignCenter, key.mask_text)
            else:
                # draw the legend
                if key.color is not None and not active:
                    qp.setPen(key.color)
                qp.drawText(key.rect, Qt.AlignCenter, key.text)

            qp.restore()

        qp.end()
示例#49
0
class PixelWidget(QWidget):
    def __init__(self, form, bufhandler):
        super(PixelWidget, self).__init__()

        self.form = form
        self.set_zoom(10)
        self.maxPixelsPerLine = 64
        self.maxPixelsTotal = 0
        self.prev_mouse_y = 0
        self.key = None
        self.buffers = None
        self.offs = 0
        self.base = 0
        self.fm = None
        self.filter_idx = 0
        self.mouseOffs = 0
        self.sync = True
        self.bh = bufhandler
        self.mouse_abs_x = 0
        self.mouse_abs_y = 0
        self.elemX = 0
        self.elemY = 0
        self.rect_x = 0
        self.rect_x_width = 0
        self.lock_width = False
        self.lock_sync = False
        self.link_pixel = True
        self.highlight_cursor = False
        self.render_data = True
        self.cur_formatter_idx = 0
        self.max_formatters = 2

        self.setMouseTracking(True)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.sh = SignalHandler()
        self.statechanged = self.sh.pw_statechanged
        self.next_filter = self.sh.pw_next_filter
        self.prev_filter = self.sh.pw_prev_filter

        self.qp = QPainter()

        self.show()

    def paintEvent(self, event):
        if not self.fm:
            return

        # set leftmost x-coordinate of graph
        zoom_level = self.get_zoom()
        self.rect_x_width = self.get_width() * zoom_level
        self.rect_x = (self.rect().width() / 2) - (self.rect_x_width / 2)

        self.qp.begin(self)

        # what is a good default font for OSX/Linux?
        self.qp.setFont(QFont(FONT_DEFAULT))

        # fill background
        self.qp.fillRect(self.rect(), Qt.black)

        content_addr = content_size = None
        if self.fm.support_selection:
            selected, start, end = ida_kernwin.read_range_selection(None)
            if selected:
                content_addr = start  #min(start, end)
                content_size = end - start  #max(start, end) - content_addr

        # use colorfilter to render image
        img = self.render_image(addr=content_addr, buf_size=content_size)

        if img:
            """
            if zoom_level > 6:
                opacity = self.qp.opacity()
                full_opacity_zoom = 40.0
                cur_opacity = (1.0 - (full_opacity_zoom - float(min(zoom_level-1, full_opacity_zoom)))/full_opacity_zoom)
                self.qp.setOpacity(1.0-cur_opacity)
            """
            # draw image
            self.qp.drawImage(
                QRect(
                    QPoint(self.rect_x, 0),
                    QPoint(self.rect_x + self.get_width() * zoom_level,
                           (self.get_pixels_total() / self.get_width()) *
                           zoom_level)), img)

            # TODO: pen color contrast
            # TODO: data export: render data
            # TODO: default fonts / OS?
            # TODO: optimization
            # FIXME: there's a bug with gaps/unmapped buffers
            if self.render_data and not self.fm.disable_data and zoom_level > 6:
                self.qp.setPen(QColor(Qt.white))
                fontsize = self.qp.font().pointSize()
                font = self.qp.font()

                font.setPointSize(zoom_level / 3)
                self.qp.setFont(font)

                opacity = self.qp.opacity()
                full_opacity_zoom = 28
                cur_opacity = (
                    1.0 - (full_opacity_zoom -
                           float(min(zoom_level - 1, full_opacity_zoom))) /
                    full_opacity_zoom)
                self.qp.setOpacity(cur_opacity)

                m = self.qp.fontMetrics()
                x = y = 0
                num_pixels_per_row = self.get_width()

                if self.cur_formatter_idx == 0:
                    sample = "%c" % (ord('X'))
                    cwidth = m.width(sample)
                    cheight = m.height()

                    for mapped, buf in self.buffers:
                        for i in range(len(buf)):
                            if mapped:
                                b = ord(buf[i])
                                data = "%c" % (chr(b) if b in range(
                                    0x20, 0x7E) else ".")

                                self.qp.drawStaticText(
                                    self.rect_x + x * zoom_level +
                                    (zoom_level - cwidth) / 2, y * zoom_level +
                                    (zoom_level - cheight) / 2,
                                    QStaticText(data))

                            x = (i + 1) % num_pixels_per_row
                            if not x:
                                y = y + 1

                elif self.cur_formatter_idx == 1:
                    sample = "%02X" % (ord('X'))
                    cwidth = m.width(sample)
                    cheight = m.height()

                    for mapped, buf in self.buffers:
                        for i in range(len(buf)):
                            if mapped:
                                data = "%02X" % ord(buf[i])

                                self.qp.drawStaticText(
                                    self.rect_x + x * zoom_level +
                                    (zoom_level - cwidth) / 2, y * zoom_level +
                                    (zoom_level - cheight) / 2,
                                    QStaticText(data))

                            x = (i + 1) % num_pixels_per_row
                            if not x:
                                y = y + 1

                self.qp.setOpacity(opacity)
                font.setPointSize(fontsize)
                self.qp.setFont(font)

        if self.show_address_range and self.fm.link_pixel:
            self.render_slider(addr=content_addr, buf_size=content_size)

        # get and draw annotations and pointers
        annotations = self.fm.on_get_annotations(
            content_addr if content_addr else self.get_address(),
            self.get_pixels_total(), self.mouseOffs)

        if annotations:
            self.render_annotations(annotations)

        self.qp.end()
        return

    def render_slider(self, addr=None, buf_size=None):
        if addr is None or buf_size is None:
            addr = self.base + self.offs
            buf_size = self.get_pixels_total()

        lowest_ea = ida_idaapi.get_inf_structure().get_minEA()
        highest_ea = ida_idaapi.get_inf_structure().get_maxEA()
        start_offs = addr - lowest_ea
        addr_space = highest_ea - lowest_ea

        perc_s = float(start_offs) / float(addr_space)
        perc_e = float(start_offs + buf_size) / float(addr_space)

        bar_width = 20

        spaces_bar = 5
        bar_x = self.rect_x - spaces_bar - bar_width
        bar_y = 5
        bar_height = self.rect().height() - 2 * bar_y
        self.qp.fillRect(bar_x, bar_y, bar_width, bar_height, QColor(0x191919))

        slider_offs_s = int(round(perc_s * bar_height))
        slider_offs_e = int(round(perc_e * bar_height))

        spaces_slider = 1
        slider_x = bar_x + spaces_slider
        slider_y = bar_y + slider_offs_s
        slider_width = bar_width - 2 * spaces_slider
        # limit slider height to bar_height
        slider_height = max(
            min(slider_offs_e - slider_offs_s,
                bar_height - (slider_y - bar_y)), 4)

        self.qp.fillRect(slider_x, slider_y, slider_width, slider_height,
                         QColor(0x404040))

        # draw addresses
        top = '%X:' % self.get_address()
        bottom = '%X' % (self.get_address() +
                         ((self.get_pixels_total() / self.get_width()) - 1) *
                         self.get_width())
        self.qp.setPen(QColor(0x808080))
        self.qp.drawText(
            self.rect_x - self.qp.fontMetrics().width(top) - bar_width -
            2 * spaces_bar,
            self.qp.fontMetrics().height(), top)
        self.qp.drawText(
            self.rect_x - self.qp.fontMetrics().width(bottom) - bar_width -
            2 * spaces_bar,
            self.rect().height() - self.qp.fontMetrics().height() / 2, bottom)
        return

    def render_image(self, addr=None, buf_size=None, cursor=True):
        size = self.size()
        self.maxPixelsTotal = self.get_width() * (size.height() /
                                                  self.pixelSize)
        if addr is None or buf_size is None:
            addr = self.base + self.offs
            buf_size = self.get_pixels_total()

        self.buffers = self.bh.get_buffers(addr, buf_size)
        img = QImage(self.get_width(),
                     size.height() / self.pixelSize, QImage.Format_RGB32)
        pixels = self.fm.on_process_buffer(self.buffers, addr,
                                           self.get_pixels_total(),
                                           self.mouseOffs)

        x = y = 0
        # transparency effect for unmapped bytes
        transparency_dark = [qRgb(0x2F, 0x4F, 0x4F), qRgb(0x00, 0x00, 0x00)]
        transparency_err = [qRgb(0x7F, 0x00, 0x00), qRgb(0x33, 0x00, 0x00)]
        for mapped, pix in pixels:
            if not mapped:
                if pix is None:
                    pix = transparency_dark[(x & 2 != 0) ^ (y & 2 != 0)]
            img.setPixel(x, y, pix)

            x = (x + 1) % self.get_width()
            if not x:
                y = y + 1

        if len(pixels) != self.get_pixels_total():
            for i in xrange(self.get_pixels_total() - len(pixels)):
                pix = transparency_err[(x & 2 != 0) ^ (y & 2 != 0)]
                img.setPixel(x, y, pix)
                x = (x + 1) % self.get_width()
                if not x:
                    y = y + 1

        if ((cursor and self.fm.highlight_cursor)
                and self.mouse_abs_x >= self.rect_x
                and self.mouse_abs_x < self.rect_x + self.rect_x_width):

            coords = self.get_coords_by_address(self.get_cursor_address())
            if coords:
                x, y = coords
            else:
                x = self.get_elem_x()
                y = self.get_elem_y()
            p = QPoint(x, y)
            img.setPixel(p, ~(img.pixelColor(p)).rgb())

        return img

    def render_annotations(self, annotations=[]):
        a_offs = 20
        base_x = self.rect_x + self.get_width() * self.pixelSize + a_offs + 10
        base_y = self.qp.fontMetrics().height()
        offs_x = 5
        offs_y = base_y

        for coords, arr_color, ann, txt_color in annotations:
            # draw arrow (experimental / WIP)
            self.qp.setPen(
                QColor(Qt.white if txt_color is None else txt_color))
            self.qp.drawText(base_x + 10, (base_y + offs_y) / 2, ann)
            target_x = target_y = None

            if coords:
                if isinstance(coords, tuple):
                    target_x, target_y = coords
                else:
                    ptr = self.get_coords_by_address(coords)
                    if ptr:
                        target_x, target_y = ptr

                if target_x is not None and target_y is not None:
                    target_x *= self.get_zoom()
                    target_y *= self.get_zoom()

                    self.qp.setPen(
                        QColor(Qt.white if arr_color is None else arr_color))
                    path = QPainterPath()
                    path.moveTo(base_x + offs_x,
                                (base_y + offs_y) / 2 - base_y / 2)

                    path.lineTo(base_x + offs_x - 4 - a_offs,
                                (base_y + offs_y) / 2 - base_y / 2)  # left
                    path.lineTo(base_x + offs_x - 4 - a_offs,
                                ((target_y / 10) * 9) +
                                self.get_zoom() / 2)  # down
                    path.lineTo(self.rect_x + target_x + self.get_zoom() / 2,
                                ((target_y / 10) * 9) +
                                self.get_zoom() / 2)  # left
                    path.lineTo(self.rect_x + target_x + self.get_zoom() / 2,
                                target_y + self.get_zoom() / 2)  # down
                    a_offs = max(a_offs - 2, 0)
                    self.qp.drawPath(path)
                else:
                    if not isinstance(coords, tuple):
                        direction = self.get_target_direction(coords)
                        if direction:
                            self.qp.setPen(
                                QColor(Qt.white
                                       if arr_color is None else arr_color))
                            m = self.qp.fontMetrics()
                            dirhint = ['', '<<', '>>'][direction]
                            cwidth = m.width("%s" % (dirhint))
                            self.qp.drawText(base_x - cwidth,
                                             (base_y + offs_y) / 2, dirhint)

            offs_y += 2 * base_y + 5
        return

    # functions that can be called by filters
    # must no be called from within on_process_buffer()
    def on_filter_request_update(self, ea=None, center=True):
        if not ea:
            self.repaint()
        else:
            curea = self.get_address()
            if ea < curea or ea >= curea + self.get_pixels_total():
                # TODO: verify that ea is valid after following operation
                if center:
                    ea -= self.get_pixels_total() / 2
                self.set_addr(ea)
            else:
                self.repaint()

    def on_filter_update_zoom(self, zoom):
        self.set_zoom(zoom)
        return

    def on_filter_update_zoom_delta(self, delta):
        self.set_zoom_delta(delta)
        return

    # end of functions that can be called by filters

    def show_help(self):
        ida_kernwin.info("%s" % PLUGIN_HELP)

    def keyPressEvent(self, event):
        if self.key is None:
            self.key = event.key()
        return

    def keyReleaseEvent(self, event):
        update = False
        key = event.key()
        modifiers = event.modifiers()

        shift_pressed = ((modifiers & Qt.ShiftModifier) == Qt.ShiftModifier)
        ctrl_pressed = ((modifiers & Qt.ControlModifier) == Qt.ControlModifier)

        if key == Qt.Key_F1 and ctrl_pressed:
            self.show_help()

        elif key == Qt.Key_G:
            addr = ask_addr(self.base + self.offs, 'Jump to address')
            if addr is not None:
                if self.sync:
                    ida_kernwin.jumpto(addr)
                else:
                    minea = ida_idaapi.get_inf_structure().get_minEA()
                    maxea = ida_idaapi.get_inf_structure().get_maxEA()
                    dst = min(max(addr, minea), maxea)
                    self.set_addr(dst)

        elif key == Qt.Key_S:
            if not self.fm.lock_sync:
                self.set_sync_state(not self.get_sync_state())
                update = True

        elif key == Qt.Key_T:
            self.render_data = not self.render_data
            self.repaint()

        elif key == Qt.Key_D:
            self.cur_formatter_idx = (self.cur_formatter_idx +
                                      1) % self.max_formatters
            self.repaint()

        elif key == Qt.Key_N:
            self.next_filter.emit()

        elif key == Qt.Key_B:
            self.prev_filter.emit()

        elif key == Qt.Key_F2:
            hlp = self.fm.help
            if hlp is None:
                hlp = 'Help unavailable'
            ida_kernwin.info('%s\n\n' % hlp)

        elif key == Qt.Key_F12:
            img = self.render_image(cursor=False)
            img = img.scaled(img.width() * self.pixelSize,
                             img.height() * self.pixelSize, Qt.KeepAspectRatio,
                             Qt.FastTransformation)
            done = False
            i = 0
            while not done:
                fname = 'IDACyber_%04d.bmp' % i
                if not os.path.isfile(fname):
                    if img.save(fname):
                        ida_kernwin.msg('File exported to %s\n' % fname)
                    else:
                        ida_kernwin.warning(
                            'Error exporting screenshot to %s.' % fname)
                    done = True
                i += 1
                if i > 40:
                    ida_kernwin.warning('Aborted. Error exporting screenshot.')
                    break

        elif key == Qt.Key_PageDown:
            self.set_offset_delta(-self.get_pixels_total())
            update = True

        elif key == Qt.Key_PageUp:
            self.set_offset_delta(self.get_pixels_total())
            update = True

        elif key == Qt.Key_Down:
            if shift_pressed:
                self.set_offset_delta(-1)
            else:
                self.set_offset_delta(-self.get_width())
            update = True

        elif key == Qt.Key_Up:
            if shift_pressed:
                self.set_offset_delta(1)
            else:
                self.set_offset_delta(self.get_width())
            update = True

        elif key == Qt.Key_Plus:
            if ctrl_pressed:
                self.set_zoom_delta(1)
            update = True

        elif key == Qt.Key_Minus:
            if ctrl_pressed:
                self.set_zoom_delta(-1)
            update = True

        self.key = None

        if update:
            if self.get_sync_state():
                ida_kernwin.jumpto(self.base + self.offs)
                self.activateWindow()
                self.setFocus()
            self.statechanged.emit()
            self.repaint()

        return

    def mouseReleaseEvent(self, event):
        self.prev_mouse_y = event.pos().y()
        self.fm.on_mb_click(event, self.get_address(), self.get_pixels_total(),
                            self.mouseOffs)

        if self.get_sync_state():
            ida_kernwin.jumpto(self.base + self.offs)
            self.activateWindow()
            self.setFocus()
            self.statechanged.emit()
        return

    def mouseDoubleClickEvent(self, event):
        if self.link_pixel and event.button() == Qt.LeftButton:
            addr = self.base + self.offs + self._get_offs_by_pos(event.pos())
            ida_kernwin.jumpto(addr)
        return

    def wheelEvent(self, event):
        delta = event.angleDelta().y() / 120

        # zoom
        if self.key == Qt.Key_Control:
            self.set_zoom_delta(delta)

        # width
        elif self.key == Qt.Key_X:
            if not self.lock_width:
                self.set_width_delta(delta)

        # offset (fine)
        elif self.key == Qt.Key_Shift:
            self.set_offset_delta(delta)

            if self.get_sync_state():
                ida_kernwin.jumpto(self.base + self.offs)
                self.activateWindow()
                self.setFocus()

        elif self.key == Qt.Key_H:
            if not self.lock_width:
                less = delta < 0
                w = -8 if less else 8
                self.set_width((self.get_width() & 0xFFFFFFF8) + w)

        # offset (coarse)
        else:
            self.set_offset_delta(delta * self.get_width())

            if self.get_sync_state():
                ida_kernwin.jumpto(self.base + self.offs)
                self.activateWindow()
                self.setFocus()

        self.statechanged.emit()
        self.repaint()
        return

    def mouseMoveEvent(self, event):
        x = event.pos().x()
        y = event.pos().y()
        within_graph = (x >= self.rect_x
                        and x < self.rect_x + self.rect_x_width)

        if within_graph:
            if event.buttons() == Qt.NoButton:
                self._update_mouse_coords(event.pos())
                self.mouseOffs = self._get_offs_by_pos(event.pos())

                if self.link_pixel and self.highlight_cursor:
                    highlight_item(
                        ida_bytes.get_item_head(self.get_cursor_address()))
                elif self.highlight_cursor:
                    unhighlight_item()

                self.setToolTip(
                    self.fm.on_get_tooltip(self.get_address(),
                                           self.get_pixels_total(),
                                           self.mouseOffs))

            # zoom
            elif self.key == Qt.Key_Control:
                self.set_zoom_delta(-1 if y > self.prev_mouse_y else 1)

            # width
            elif self.key == Qt.Key_X:
                if not self.lock_width:
                    self.set_width_delta(-1 if y > self.prev_mouse_y else 1)

            elif self.key == Qt.Key_H:
                if not self.lock_width:
                    less = y > self.prev_mouse_y
                    delta = -16 if less else 16
                    self.set_width((self.get_width() & 0xFFFFFFF0) + delta)

            # scrolling (offset)
            elif y != self.prev_mouse_y:
                # offset (fine)
                delta = y - self.prev_mouse_y

                # offset (coarse)
                if self.key != Qt.Key_Shift:
                    delta *= self.get_width()

                self.set_offset_delta(delta)

            self.prev_mouse_y = y
            self.x = x
            self.statechanged.emit()
            self.repaint()
        return

    def set_sync_state(self, sync):
        self.sync = sync

    def get_sync_state(self):
        return self.sync

    def get_filter_idx(self):
        return self.filter_idx

    def set_filter(self, fltobj, idx):
        if self.fm:
            self.fm.on_deactivate()
        if fltobj:
            self.fm = fltobj
            """load filter config"""
            self.set_sync_state(self.fm.sync)
            self.lock_width = self.fm.lock_width
            self.set_width(self.fm.width)
            self.lock_sync = self.fm.lock_sync
            self.show_address_range = self.fm.show_address_range
            # disabled for now
            # self.set_zoom(self.fm.zoom)
            self.link_pixel = self.fm.link_pixel
            self.highlight_cursor = self.fm.highlight_cursor
            self.statechanged.emit()
            """load filter config end"""

            self.fm.on_activate(idx)
            self.filter_idx = idx
            unhighlight_item()
            self.repaint()

    def set_addr(self, ea, new_cursor=None):
        base = self.bh.get_base(ea)

        self._set_base(base)
        self._set_offs(ea - base)

        if new_cursor:
            self.set_cursor_address(new_cursor)
            if self.highlight_cursor:
                highlight_item(ea)

        self.repaint()

    def get_zoom(self):
        return self.pixelSize

    def set_zoom(self, zoom):
        self.pixelSize = zoom

    def set_zoom_delta(self, dzoom):
        self.set_zoom(max(1, self.pixelSize + dzoom))
        return

    def get_width(self):
        return self.maxPixelsPerLine

    def get_pixels_total(self):
        return self.maxPixelsTotal

    def get_address(self):
        return self.base + self.offs

    def get_cursor_address(self):
        return self.get_address() + self.mouseOffs

    def set_cursor_address(self, ea):
        self.mouseOffs = ea - self.get_address()

    def get_coords_by_address(self, address):
        base = self.get_address()
        # if address is visible in current window
        if address >= base and address < base + self.get_pixels_total():
            offs = address - base
            x = offs % self.get_width()
            y = offs / (self.get_width())
            return (x, y)
        return None

    def get_target_direction(self, address):
        base = self.get_address()
        # if address is visible in current window
        direction = None
        if address >= base and address < base + self.get_pixels_total():
            direction = 0
        elif address < base:
            direction = 1
        else:
            direction = 2
        return direction

    def set_width(self, width):
        self.maxPixelsPerLine = max(1, width)

    def set_width_delta(self, dwidth):
        self.maxPixelsPerLine = max(1, self.maxPixelsPerLine + dwidth)

    def set_offset_delta(self, doffs):
        newea = self.base + self.offs - doffs
        minea = ida_idaapi.get_inf_structure().get_minEA()
        maxea = ida_idaapi.get_inf_structure().get_maxEA()
        if doffs < 0:
            delta = doffs if newea < maxea else doffs - (maxea - newea)
        else:
            delta = doffs if newea >= minea else doffs - (minea - newea)
        self._set_offs(self.offs - delta)

    def _get_offs_by_pos(self, pos):
        elemX = self.get_elem_x()
        elemY = self.get_elem_y()
        offs = elemY * self.get_width() + elemX
        return offs

    def _update_mouse_coords(self, pos):
        x = pos.x()
        y = pos.y()
        self.mouse_abs_x = x
        self.mouse_abs_y = y

        self.elemX = max(
            0,
            min((max(0, x - self.rect_x)) / self.pixelSize,
                self.get_width() - 1))
        self.elemY = min(y / self.pixelSize,
                         self.maxPixelsTotal / self.get_width() - 1)

    def get_elem_x(self):
        return self.elemX

    def get_elem_y(self):
        return self.elemY

    def _set_offs(self, offs):
        self.offs = offs

    def _set_base(self, ea):
        self.base = ea
示例#50
0
    def redraw(self, painter: QtGui.QPainter, vertical_offset: float = 0) -> None:
        # if the button is hidden then there is nothing to draw
        if self._state == ICWidgetState.Hidden:
            return

        # the size of the button is determined by the size of the widget
        tmp_width = painter.device().width()
        tmp_height = painter.device().height()

        # define the rectangle to draw the button
        rect = QtCore.QRectF(5, 5, tmp_width - 10, tmp_height - 10)

        # a linear gradient brush is used to fill the button
        brush = QtGui.QLinearGradient(rect.topRight(), rect.bottomRight())
        # if the widget is transparent then the rect is drawn using background color
        if self._state == ICWidgetState.Transparent:
            brush.setColorAt(0, self.background_color)
            brush.setColorAt(1, self.background_color)
        else:
            brush.setColorAt(0, self._button_color_light)
            brush.setColorAt(1, self._button_color_dark)

        # set the brush
        painter.setBrush(brush)

        # define the pen that with rounded cap and join style
        if not self.in_focus:
            pen = QtGui.QPen()
            pen.setWidth(1)
        else:
            pen = QtGui.QPen(self.focus_color)
            pen.setWidth(3)
        pen.setCapStyle(Qt.RoundCap)
        pen.setJoinStyle(Qt.RoundJoin)

        # set the pen to use the brush and set the painter pen
        if not self.in_focus:
            pen.setBrush(brush)
        painter.setPen(pen)

        # define the path that needs to be drawn
        path = QtGui.QPainterPath()
        path.setFillRule(Qt.WindingFill)
        path.addRoundedRect(rect, 10, 10)
        painter.drawPath(path)

        # draw the text only if the button is visible
        if self._state in (ICWidgetState.VisibleEnabled, ICWidgetState.VisibleDisabled):
            # define the font for drawing
            fnt = painter.font()
            fnt.setBold(True)
            fnt.setPixelSize(self._text_size)
            painter.setFont(fnt)

            # select the font color based on if the button is enabled or not
            if self._state == ICWidgetState.VisibleEnabled:
                pen.setColor(self._text_color_enabled)
            else:
                pen.setColor(self._text_color_disabled)
            painter.setPen(pen)

            # draw the text
            rect = QtCore.QRectF(10, tmp_height / 2 - 0.5 * (self._text_size + 5) + vertical_offset, tmp_width - 20, self._text_size + 5)
            painter.drawText(rect, Qt.AlignCenter, str(self._name))
示例#51
0
    def paintEvent(self, event: QPaintEvent):
        _start = perf_counter()
        num = self.num_tabs
        selected = self.selected
        arrow_width = self._arrow_width
        height = self.height()
        width = self._button_width
        first_width = self._first_button_width
        button = self._button_path
        button_box = QRect(0, 0, width + arrow_width, height)
        first_box = QRect(0, 0, first_width + arrow_width, height)
        icon_area = QRect(arrow_width + 10, 0, max(48, width / 2), height)
        text_box = QRect(arrow_width, 0, width - arrow_width, height)
        text_flags = Qt.AlignCenter | Qt.AlignVCenter
        states = self.states

        painter = QPainter(self)
        region = event.region()
        painter.setClipRegion(region)
        #torender = self._tabs_within(event.region())
        #print("regions:")
        #for rect in event.region().rects():
        #    print(" -  ", rect)
        #painter.setPen(Qt.NoPen)
        painter.setPen(
            QPen(Qt.black, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        titleFont = painter.font()
        titleFont.setPointSizeF(14)
        titleFont.setBold(True)
        painter.setFont(titleFont)

        painter.translate(num * width + first_width, 0)

        if region.intersects(painter.transform().mapRect(button_box)):
            painter.setBrush(states[num].get_color(num == selected))
            painter.drawPath(self._last_button_path)

        for i in reversed(range(num)):
            painter.translate(-width, 0)
            if not region.intersects(painter.transform().mapRect(button_box)):
                continue

            painter.setBrush(states[i].get_color(i == selected))
            painter.drawPath(button)

            if states[i].state == State.ACTIVE:
                painter.save()
                painter.setPen(Qt.NoPen)
                gw = (width + self._arrow_width) * 2
                gradient = QLinearGradient(0, 0, gw, 0)
                value = self._working_anim.value
                gradient.setColorAt(max(0.0, value - 0.2),
                                    QColor(255, 255, 255, 0))
                gradient.setColorAt(value, QColor(255, 255, 255, 180))
                gradient.setColorAt(min(1.0, value + 0.2),
                                    QColor(255, 255, 255, 0))
                brush = QBrush(gradient)
                brush.setTransform(brush.transform().translate(-gw / 4, 0))
                gradient_height = int(height * 0.2)
                painter.setBrush(brush)
                #painter.setClipRect(0, 0, width+self._arrow_width, gradient_height)
                #painter.drawPath(button)
                #painter.setClipRect(0, height-gradient_height, width+self._arrow_width, gradient_height)
                painter.drawPath(button)
                self._active_box = painter.transform().mapRect(button_box)
                painter.restore()

            #if states[i].icon:
            #    states[i].icon.paint(painter, icon_area)

            text = states[i].text
            if text:
                _, _, short = text.rpartition('-')
                painter.drawText(text_box, text_flags, short.capitalize())

        if region.intersects(first_box):
            painter.resetTransform()
            painter.setBrush(State.UNKNOWN.get_color(-1 == selected))
            painter.drawPath(self._first_button_path)

            if self.is_running:
                icon = self.style().standardIcon(QStyle.SP_MediaStop)
            else:
                icon = self.style().standardIcon(QStyle.SP_MediaPlay)

            size = min(self._first_button_width, self.height()) * 0.8
            painter.translate(5, (self.height() - size) / 2)
            icon.paint(painter, QRect(0, 0, size, size))

        _end = perf_counter()
        if not self._paint_times:
            self._paint_times = times = []
        else:
            times = self._paint_times
        times.append(_end - _start)
        if len(times) > 60:
            avg = sum(times) / len(times) * 1000000
            print("Average render time %.2fns" % (avg, ))
            self._paint_times = None
示例#52
0
class Renderer(QFrame):
    update_time_signal = pyqtSignal(int)
    pause_signal = pyqtSignal()

    def __init__(self, beatmap, replays, events, start_speed, paint_info, \
        statistic_functions):
        super().__init__()
        self.setMinimumSize(GAMEPLAY_WIDTH + GAMEPLAY_PADDING_WIDTH * 2,
            GAMEPLAY_HEIGHT + GAMEPLAY_PADDING_HEIGHT * 2)
        self.beatmap = beatmap
        # list of timestamps to highlight the frames of in a different color
        self.events = events
        # whether to show some information about each player and their cursors
        self.should_paint_info = paint_info
        # functions to display info for in the visualizer
        self.statistic_functions = statistic_functions
        # whether we should paint the frametime graph
        self.paint_frametime = False
        self.painter = QPainter()
        self.scale = 1
        self.x_offset = 0
        self.y_offset = 0
        # a map of QRect to Player, where the rectangle is the location of the
        # player's info on the screen. Updated every frame (even though it's
        # currently static except for the width, it may differ from frame to
        # frame in the future)
        self.player_info_positions = {}
        # players that have been disabled by the users and we don't want to
        # draw cursor movements for
        self.disabled_players = []

        self.setMouseTracking(True)

        # hitobjs currently on screen
        self.hitobjs_to_draw = []
        # we actually care about more than just the hitobjs on screen when
        # drawing error bar markers, so keep track of those hitobjs here.
        # this will (should) be a superset of ``hitobjs_to_draw``
        self.hitobjs_to_draw_hits_for = []
        # and we care about *less* than the hitobjs in hitobjs_to_draw when
        # drawing judgment indicators, since these disappear sooner. This will
        # be a subset of ``hitobjs_to_draw``.
        # TODO clean up this code, these lists shouldn't exist, instead hitobjs
        # should be marked with ``draw_judgment_indicators_for`` attributes
        # or something
        self.hitobjs_to_draw_judgment_indicators_for = []

        self.use_hr = any(Mod.HR in replay.mods for replay in replays)
        self.use_ez = any(Mod.EZ in replay.mods for replay in replays)
        if beatmap:
            self.hit_objects = beatmap.hit_objects(hard_rock=self.use_hr,
                easy=self.use_ez)
            self.playback_end = self.get_hit_endtime(self.hit_objects[-1])

            ar = beatmap.ar(hard_rock=self.use_hr, easy=self.use_ez)
            od = beatmap.od(hard_rock=self.use_hr, easy=self.use_ez)
            cs = beatmap.cs(hard_rock=self.use_hr, easy=self.use_ez)
            # see https://osu.ppy.sh/help/wiki/Beatmapping/Approach_rate
            if ar <= 5:
                self.preempt = 1200 + 600 * (5 - ar) / 5
                self.fade_in = 800 + 400 * (5 - ar) / 5
            else:
                self.preempt = 1200 - 750 * (ar - 5) / 5
                self.fade_in = 800 - 500 * (ar - 5) / 5

            (hitwindow_50, hitwindow_100, hitwindow_300) = hitwindows(od)
            self.hitwindow_50 = hitwindow_50
            self.hitwindow_100 = hitwindow_100
            self.hitwindow_300 = hitwindow_300

            # how much to scale our error bar by from its 'standard' size, where
            # each ms of error is a pixel.
            self.error_bar_width_factor = ERROR_BAR_WIDTH / (hitwindow_50 * 2)

            self.hitcircle_radius = hitradius(cs)
            # loading stuff
            self.is_loading = True
            self.num_hitobjects = len(self.hit_objects)
            # not fully accurate, but good enough
            self.num_sliders = self.num_hitobjects
            self.sliders_current = 0
            self.thread = threading.Thread(target=self.process_sliders)
            self.thread.start()
            self.has_beatmap = True
        else:
            self.playback_end = 0
            self.is_loading = False
            self.has_beatmap = False

        # if this is nonnull, when we finish loading sliders we will seek to
        # this position. Set in ``seek_to`` if it is called when we're loading
        self.seek_to_when_loaded = None
        # whether the previous frame was a loading frame or not, used to
        # determine when we came out of a loading state
        self.previously_loading = False

        # replay stuff
        self.num_replays = len(replays)
        self.players = []
        for i, replay in enumerate(replays):
            color = QColor().fromHslF(i / self.num_replays, 0.75, 0.5)
            player = Player(replay=replay, pen=QPen(color))
            self.players.append(player)

        self.playback_start = 0
        if self.num_replays > 0:
            self.playback_start = min(min(player.t) for player in self.players)
            self.playback_end = max(max(player.t) for player in self.players)

        # always start at 0, unless our playback_start is negative (meaning we
        # have negative frames)
        self.playback_start = min(self.playback_start, 0)

        # if our hitobjs are hard_rock versions, flip any player *without* hr
        # so they match other hr players.
        if self.use_hr:
            for player in self.players:
                if Mod.HardRock not in player.mods:
                    for d in player.xy:
                        d[1] = 384 - d[1]

        # clock stuff
        self.clock = Timer(start_speed, self.playback_start)
        self.paused = False
        self.play_direction = 1

        # render stuff
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.next_frame_from_timer)
        # 62 fps (1000ms / 60frames but the result can only be a integer)
        self.timer.start(1000/60)

        # black background
        pal = QPalette()
        pal.setColor(QPalette.Background, Qt.black)
        self.setAutoFillBackground(True)
        self.setPalette(pal)

        # Settings that are changeable from the control's setting button.
        # If `True`, don't draw crosses, and draw the line in grey if the user
        # was not pressing any keys in the start frame of that line.
        self.raw_view = False
        self.draw_hitobjects = True
        self.draw_approach_circles = True
        # how many frames for each replay to draw on screen at a time
        self.num_frames_on_screen = 15
        self.only_color_keydowns = False
        self.should_draw_hit_error_bar = True
        # TODO expose this as a setting somewhere? it's not toggleable anywhere
        # currently
        self.should_draw_judgment_indicators = True

        self.next_frame()

        self.hitobj_to_judgments = {}
        cg = KeylessCircleguard()
        self.can_access_judgments = self.num_replays == 1 and cg.map_available(replays[0])
        if self.can_access_judgments:
            r = replays[0]

            self.judgments = cg.judgments(r, beatmap=self.beatmap)
            # associate each hitobject with a judgment. Only hitobjs which are
            # spinners won't be associated in this mapping (since core doesn't
            # generate a judgment for them yet)
            for judgment in self.judgments:
                # use the hitobj time as our key. This will work fine for ranked
                # maps (no two hitobjs can be placed at the same time) but may
                # break for aspire, loved, or crazy graveyarded maps. Needs
                # testing.
                # A way around this is to simply store the slider hitobj in
                # circlecore's hitobjs, or convert core to using slider's
                # hitobjs again (or make them subclasses, or some such)
                self.hitobj_to_judgments[judgment.hitobject.t] = judgment


    def resizeEvent(self, event):
        width = event.size().width() - GAMEPLAY_PADDING_WIDTH * 2
        height = event.size().height() - GAMEPLAY_PADDING_HEIGHT * 2
        y_scale = height / GAMEPLAY_HEIGHT
        x_scale = width / GAMEPLAY_WIDTH
        if GAMEPLAY_WIDTH * y_scale > width:
            self.scale = x_scale
            self.y_offset = (height - GAMEPLAY_HEIGHT * x_scale) / 2
            self.x_offset = 0
        else:
            self.scale = y_scale
            self.y_offset = 0
            self.x_offset = (width - GAMEPLAY_WIDTH * y_scale) / 2

    def _x(self, position):
        return (self.x_offset + GAMEPLAY_PADDING_WIDTH +
            self.scaled_number(position))

    def _y(self, position):
        return (self.y_offset + GAMEPLAY_PADDING_HEIGHT +
            self.scaled_number(position))

    def scaled_point(self, x, y):
        return QPointF(self._x(x), self._y(y))

    def scaled_number(self, n):
        return n * self.scale

    def next_frame_from_timer(self):
        """
        Has the same effect as next_frame except if paused, where it returns.
        This is to allow the back/forward buttons to advance frame by frame
        while still paused (as they connect directly to next and previous
        frame), while still pausing the automatic timer advancement.
        """
        if self.paused:
            # ignore our paused state if we're still loading sliders, or else if
            # we pause before the sliders are done loading we'll deadlock
            # ourselves
            if self.is_loading:
                self.update()
                return
            # if we wanted to seek to somewhere while we were loaded, and we
            # have just come out of a loading state, ignore paused and seek to
            # that position
            if self.previously_loading and self.seek_to_when_loaded:
                self.seek_to(self.seek_to_when_loaded)
                self.previously_loading = False
            return
        self.next_frame()

    def next_frame(self, stepping_backwards=False):
        """
        Prepares the next frame.

        If we have just set our current time to be less than what it was the
        previous time next_frame was called, pass stepping_backwards=True so
        the correct frame can be chosen when searching the frame list.
        """
        # just update the frame if currently loading
        if self.is_loading:
            self.previously_loading = True
            self.update()
            return

        current_time = self.clock.get_time()
        # if we're at the end of the track or are at the beginning of the track
        # (and thus are reversing), pause and dont update
        if current_time > self.playback_end or current_time < self.playback_start:
            self.pause_signal.emit()
            return

        # This is the solution to the issue of stepping forward/backwards
        # getting stuck on certain frames - we can fix it for stepping forward
        # by always preferring the right side when searching our array, but when
        # stepping backwards we need to prefer the left side instead.
        side = "left" if stepping_backwards else "right"
        for player in self.players:
            player.end_pos = np.searchsorted(player.t, current_time, side)
            # for some reason side=right and side=left differ by 1 even when
            # the array has no duplicates, so only account for that in the
            # right side case
            if side == "right":
                player.end_pos -= 1

            player.start_pos = 0
            if player.end_pos >= self.num_frames_on_screen:
                player.start_pos = player.end_pos - self.num_frames_on_screen

        if self.has_beatmap:
            self.get_hitobjects()
        self.update_time_signal.emit(current_time)
        self.update()

    def get_hitobjects(self):
        # get currently visible hitobjects
        current_time = self.clock.get_time()
        found_all = False
        # TODO optimize this by tracking our current hitobj index, this iterates
        # through half the hitobjects of the map on average (O(1) best case and
        # O(n) worst case) which can't be good for performance
        index = 0
        self.hitobjs_to_draw = []
        self.hitobjs_to_draw_hits_for = []
        self.hitobjs_to_draw_judgment_indicators_for = []
        while not found_all:
            current_hitobj = self.hit_objects[index]
            hit_t = current_hitobj.time.total_seconds() * 1000
            if isinstance(current_hitobj, (Slider, Spinner)):
                hit_end = self.get_hit_endtime(current_hitobj) + self.fade_in
            else:
                hit_end = hit_t + self.hitwindow_50 + self.fade_in
            if hit_t > current_time - JUDGMENT_INDICATOR_THRESHOLD:
                self.hitobjs_to_draw_judgment_indicators_for.append(current_hitobj)
            if hit_t > current_time - ERROR_BAR_HIT_THRESHOLD:
                self.hitobjs_to_draw_hits_for.append(current_hitobj)
            if hit_t - self.preempt < current_time < hit_end:
                self.hitobjs_to_draw.append(current_hitobj)

            elif hit_t > current_time:
                found_all = True
            if index == self.num_hitobjects - 1:
                found_all = True
            index += 1

    def paintEvent(self, _event):
        """
        Called whenever self.update() is called
        """
        self.painter.begin(self)
        self.painter.setRenderHint(QPainter.TextAntialiasing, True)
        self.painter.setRenderHint(QPainter.Antialiasing, True)
        self.painter.setPen(PEN_WHITE)
        _pen = self.painter.pen()
        # loading screen
        if self.is_loading:
            if self.thread.is_alive():
                self.draw_loading_screen()
                self.painter.end()
                return
            else:
                self.is_loading = False
                self.clock.reset()
                self.painter.end()
                return
        # beatmap
        if self.has_beatmap:
            self.paint_beatmap()
        # cursors
        for player in self.players:
            self.paint_cursor(player)
        # other info
        self.painter.setPen(_pen)
        self.paint_border()
        if self.should_paint_info:
            self.paint_info()
        if self.paint_frametime:
            self.paint_frametime_graph()
        self.painter.end()

    def paint_border(self):
        PEN_WHITE.setWidth(self.scaled_number(1))
        self.painter.setPen(PEN_WHITE)
        self.painter.setOpacity(0.25)
        self.painter.drawRect(QRectF(self.scaled_point(0, 0),
            self.scaled_point(GAMEPLAY_WIDTH, GAMEPLAY_HEIGHT)))

    def paint_cursor(self, player):
        """
        Draws a cursor.

        Arguments:
            Player player: player to draw the cursor of.
        """
        # don't draw anything if the player is disabled
        if player in self.disabled_players:
            return
        alpha_step = 1 / self.num_frames_on_screen
        pen = player.pen
        width = WIDTH_LINE_RAW_VIEW if self.raw_view else WIDTH_LINE
        pen.setWidth(self.scaled_number(width))
        PEN_HIGHLIGHT.setWidth(self.scaled_number(width))
        self.painter.setPen(pen)
        highlighted_pen = False
        for i in range(player.start_pos, player.end_pos):
            highlight = any((player.t[i + 1] in self.events, player.t[i] in
                self.events))
            if highlight and not highlighted_pen:
                self.painter.setPen(PEN_HIGHLIGHT)
                highlighted_pen = True
            elif not highlight and highlighted_pen:
                self.painter.setPen(pen)
                highlighted_pen = False
            grey_out = False
            # only grey out lines if we're in raw view (crosses are greyed out
            # instead in the normal view)
            if self.raw_view:
                # grey out if we don't have a keypress at the start
                if not bool(player.k[i]):
                    grey_out = True
                # grey out if we're only coloring keydowns and this is not a
                # keydown
                if self.only_color_keydowns and not bool(player.keydowns[i]):
                    grey_out = True
            self.draw_line((i - player.start_pos) * alpha_step, player.xy[i],
                    player.xy[i + 1], grey_out=grey_out)
        pen.setWidth(self.scaled_number(WIDTH_CROSS))
        self.painter.setPen(pen)
        for i in range(player.start_pos, player.end_pos+1):
            alpha = (i - player.start_pos) * alpha_step
            xy = player.xy[i]
            k = player.k[i]
            t = player.t[i]
            highlight = t in self.events
            # grey out only if no keys are held by default
            grey_out = not bool(k)
            # but override if we're only coloring keydowns and this is not a
            # keydown
            if self.only_color_keydowns and not bool(player.keydowns[i]):
                grey_out = True
            self.draw_cross(alpha, xy, grey_out=grey_out, highlight=highlight)
        # reset alpha
        self.painter.setOpacity(1)

    def paint_beatmap(self):
        # draw playfield judgment indicators (yellow/green/blue circles under
        # hitobjs) before drawing hitobjs so they don't cover hitobjs
        # (though to be honest it doesn't make much of a difference either way)

        if self.should_draw_judgment_indicators and self.can_access_judgments:
            for hitobj in self.hitobjs_to_draw_hits_for:
                if isinstance(hitobj, Spinner):
                    continue

                judgment = self.hitobj_to_judgments[self.get_hit_time(hitobj)]

                if judgment.type is JudgmentType.Miss:
                    # misses don't have an intrinsic event time, so just use
                    # their hitobj's time
                    t = judgment.hitobject.time
                else:
                    t = judgment.time

                # don't draw hits that haven't happened yet
                if t <= self.clock.get_time():
                    self.draw_judgment_indicator(hitobj, judgment)
            self.painter.setBrush(BRUSH_BLANK)

        for hitobj in self.hitobjs_to_draw[::-1]:
            self.draw_hitobject(hitobj)

        # only draw hit error bars if there's only one replay
        if self.should_draw_hit_error_bar and self.can_access_judgments:
            self.draw_hit_error_bar()

            for hitobj in self.hitobjs_to_draw_hits_for:
                # core doesn't calculate judgmnets for spinners yet, TODO
                # implement this when core does
                if isinstance(hitobj, Spinner):
                    continue

                judgment = self.hitobj_to_judgments[self.get_hit_time(hitobj)]
                # don't draw any judgment bars for misses
                if judgment.type is JudgmentType.Miss:
                    continue
                # don't draw hits that haven't happened yet
                if judgment.t <= self.clock.get_time():
                    self.draw_hit(hitobj, judgment)

    def paint_info(self):
        """
        Draws various info about the replays in the upper left corner.
        """
        # our current y coordinate for drawing info. Modified throughout this
        # function
        y = 15

        PEN_WHITE.setWidth(1)
        self.painter.setPen(PEN_WHITE)
        self.painter.setOpacity(1)
        ms = round(self.clock.get_time())
        text = f"{ms}"
        self.painter.drawText(5, y, text)
        # we don't use a monospaced font, so our ms text may vary by as much as
        # 10 pixels in width (possibly more, haven't checked rigorously). If
        # we just drew our minute:seconds text directly after it, the position
        # of that text would constantly flicker left and right, since the ms
        # text (and thus its width) changes every single frame. To fix this,
        # only increment widths in multiples of 10. (This will not fix the issue
        # if the text width happens to hover exactly around a multiple of 10,
        # but there's not much to be done in that case).
        text_width = self.painter.boundingRect(5, y, 0, 0, 0, text).width()
        if text_width < 50:
            x = 50
        elif text_width < 60:
            x = 60
        elif text_width < 70:
            x = 70
        elif text_width < 80:
            x = 80
        else:
            # something crazy is going on, give up and just use text_width
            x = text_width

        # now some dirty code to deal with negattive times
        minutes = int(ms / (1000 * 60))
        seconds = ms // 1000
        seconds_negative = seconds < 0
        # pytohn modulo returns positive even when ``seconds_total`` is negative
        seconds = seconds % 60
        if seconds_negative:
            # ``seconds`` can be 0 and 59 but not 60, so use 59 instead of 60
            seconds = 59 - seconds
        sign = ""
        if minutes < 0 or seconds_negative:
            sign = "-"
            minutes = abs(minutes)
            seconds = abs(seconds)

        self.painter.drawText(5 + 4 + x, y,
            f"ms ({sign}{minutes:01}:{seconds:02})")

        self.player_info_positions = {}
        if self.num_replays > 0:
            for player in self.players:
                def _set_opacity(opacity):
                    if player in self.disabled_players:
                        opacity /= 2.4
                    self.painter.setOpacity(opacity)

                y += 13
                pen = player.pen
                self.painter.setPen(PEN_BLANK)
                self.painter.setBrush(QBrush(pen.color()))
                keys = Key(int(player.k[player.end_pos]))
                _set_opacity(1 if Key.M1 in keys else 0.3)
                self.painter.drawRect(5, y - 9, 10, 10)
                _set_opacity(1 if Key.M2 in keys else 0.3)
                self.painter.drawRect(18, y - 9, 10, 10)
                _set_opacity(1)
                self.painter.setPen(pen)
                info_text = (f"{player.username} {player.mods.short_name()}: "
                    f"{player.xy[player.end_pos][0]:.2f}, "
                    f"{player.xy[player.end_pos][1]:.2f}")
                self.painter.drawText(31, y, info_text)
                # not sure why we need to do ``y - 9`` instead of 9 here,
                # our ``drawText`` call is perfectly happy to accept ``y`` but
                # we need to pass ``y - 9`` to our ``drawRect`` calls...maybe 9
                # was a manually determined number that causes the text to align
                # with the drawn boxes?
                info_pos = self.painter.boundingRect(5, y - 9, 0, 0, 0,
                    info_text)
                info_pos = Rect(info_pos.x(), info_pos.y(), info_pos.width(),
                    info_pos.height())
                # unfortunately the rects overlap if we don't make this manual
                # adjustment; would like to figure out why but this works for
                # now.
                info_pos.height -= 3
                # our bounding rect starts at 5 but the text starts at 31, so
                # we need to increase the width by the difference to account
                info_pos.width += 31 - 5
                self.player_info_positions[info_pos] = player

            self.painter.setOpacity(1)
            self.painter.setPen(PEN_WHITE)
            if self.num_replays == 2:
                try:
                    y += 13
                    p1 = self.players[0]
                    p2 = self.players[1]
                    distance = math.sqrt(((p1.xy[p1.end_pos][0] - p2.xy[p2.end_pos][0]) ** 2) +
                                         ((p1.xy[p1.end_pos][1] - p2.xy[p2.end_pos][1]) ** 2))
                    self.painter.drawText(5, y, f"{int(distance)}px apart")
                except IndexError:
                    # we may only have data from one cursor at the moment
                    pass

            if self.num_replays == 1 and self.has_beatmap:
                y += 13
                player = self.players[0]
                current_t = timedelta(milliseconds=int(self.clock.get_time()))
                closest_hitobj = self.beatmap.closest_hitobject(current_t)
                if self.use_hr:
                    closest_hitobj = closest_hitobj.hard_rock
                distance = self.distance_between(player.xy[player.end_pos],
                    closest_hitobj)

                # show "x px inside hitobj" instead of a negative distance
                inside = False
                if distance < 0:
                    inside = True
                    distance = abs(distance)

                inside_from = "inside" if inside else "from"
                text = f"{distance:0.2f}px {inside_from} closest hitobj"
                self.painter.drawText(5, y, text)

            for function in self.statistic_functions:
                y += 13
                xys = [player.xy for player in self.players]
                indices = [player.end_pos for player in self.players]
                result = function(xys, indices)
                self.painter.drawText(5, y, f"{function.__name__}: {result}")


    def draw_line(self, alpha, start, end, grey_out=False):
        """
        Draws a line at the given alpha level from the start point to the end
        point.

        Arguments:
            Float alpha: The alpha level (from 0.0 to 1.0) to set the line to.
            List start: The X&Y position of the start of the line.
            List end: The X&Y position of the end of the line.
            Boolean grey_out: Whether to grey out the line or not.
        """
        if grey_out:
            prev_pen = self.painter.pen()
            PEN_GREY_INACTIVE.setWidth(self.scaled_number(WIDTH_LINE_RAW_VIEW))
            self.painter.setPen(PEN_GREY_INACTIVE)

        self.painter.setOpacity(alpha)
        self.painter.drawLine(self.scaled_point(start[0], start[1]),
            self.scaled_point(end[0], end[1]))

        if self.raw_view and grey_out:
            self.painter.setPen(prev_pen)

    def draw_cross(self, alpha, point, grey_out, highlight):
        """
        Draws a cross.

        Args:
           Float alpha: The alpha level from 0.0-1.0 to set the cross to.
           List point: The X and Y position of the cross.
           Boolean grey_out: Whether to grey out the cross or not.
           Boolean highlight: Whether to highlight the cross or not. This takes
               precedence over ``grey_out`` if both are set.
        """
        # crosses can clutter the screen sometimes, don't draw them if raw view
        # is on
        if self.raw_view:
            return
        prev_pen = None
        if highlight:
            prev_pen = self.painter.pen()
            PEN_HIGHLIGHT.setWidth(self.scaled_number(WIDTH_CROSS))
            self.painter.setPen(PEN_HIGHLIGHT)
        elif grey_out:
            prev_pen = self.painter.pen()
            PEN_GREY_INACTIVE.setWidth(self.scaled_number(WIDTH_CROSS))
            self.painter.setPen(PEN_GREY_INACTIVE)
        half_width = LENGTH_CROSS/2
        x = point[0]
        y = point[1]
        x1 = x + half_width
        x2 = x - half_width
        y1 = y + half_width
        y2 = y - half_width

        self.draw_line(alpha, [x1, y1], [x2, y2])
        self.draw_line(alpha, [x2, y1], [x1, y2])
        if grey_out or highlight:
            self.painter.setPen(prev_pen)


    def draw_hitobject(self, hitobj):
        """
        Calls the corresponding function to draw ``hitobj``.
        """
        if not self.draw_hitobjects:
            return
        if isinstance(hitobj, Circle):
            self.draw_hitcircle(hitobj)
            self.draw_approachcircle(hitobj)
        if isinstance(hitobj, Slider):
            self.draw_slider(hitobj)
        if isinstance(hitobj, Spinner):
            self.draw_spinner(hitobj)

    def draw_hitcircle(self, hitobj):
        """
        Draws a circle hitobject.
        """
        current_time = self.clock.get_time()
        fade_out = max(0, ((current_time - self.get_hit_time(hitobj)) / self.hitwindow_50))
        opacity = min(1, ((current_time - (self.get_hit_time(hitobj) - self.preempt)) / self.fade_in))
        opacity = max(0, min(1, opacity-fade_out))
        p = hitobj.position

        # the pen width grows outwards and inwards equally (preferring outwards
        # if the width is odd I think), so we need to tell it to start drawing
        # half of the pen's width away from the radius for the final circle to
        # have radius `self.hitcircle_radius`.
        r = self.scaled_number(self.hitcircle_radius - WIDTH_CIRCLE_BORDER / 2)

        # normal white hitobj
        pen = PEN_WHITE
        brush = BRUSH_GRAY

        if self.can_access_judgments:
            judgment = self.hitobj_to_judgments[self.get_hit_time(hitobj)]
            if judgment.type is JudgmentType.Miss:
                # hitobj was missed, tint red
                pen = PEN_RED_TINT
                brush = BRUSH_GRAY_RED_TINT

        pen.setWidth(self.scaled_number(WIDTH_CIRCLE_BORDER))
        self.painter.setPen(pen)
        self.painter.setOpacity(opacity)
        self.painter.setBrush(brush)

        self.painter.drawEllipse(self.scaled_point(p.x, p.y), r, r)
        self.painter.setBrush(BRUSH_BLANK)

    def draw_spinner(self, hitobj):
        """
        Draws a spinner hitobject.
        """
        current_time = self.clock.get_time()
        if self.get_hit_endtime(hitobj) - current_time < 0:
            return
        radius = GAMEPLAY_HEIGHT / 2
        fade_out = max(0, ((current_time - self.get_hit_endtime(hitobj)) / self.hitwindow_50))
        opacity = min(1, ((current_time - (self.get_hit_time(hitobj) - self.preempt)) / self.fade_in))
        opacity = max(0, min(1, opacity-fade_out))
        scale = min(1, (self.get_hit_endtime(hitobj) - current_time) / (self.get_hit_endtime(hitobj) - self.get_hit_time(hitobj)))
        radius = radius * scale

        PEN_WHITE.setWidth(self.scaled_number(WIDTH_CIRCLE_BORDER / 2))
        self.painter.setPen(PEN_WHITE)
        self.painter.setOpacity(opacity)
        self.painter.drawEllipse(self.scaled_point(GAMEPLAY_WIDTH / 2, GAMEPLAY_HEIGHT / 2),
            self.scaled_number(radius), self.scaled_number(radius))

    def draw_approachcircle(self, hitobj):
        """
        Draws the approach circle of a circle hitobject.
        """
        if not self.draw_approach_circles:
            return
        current_time = self.clock.get_time()
        if self.get_hit_time(hitobj) - current_time < 0:
            return
        opacity = min(1, ((current_time - (self.get_hit_time(hitobj) - self.preempt)) / self.fade_in))
        opacity = max(0, min(1, opacity))
        scale = max(1, ((self.get_hit_time(hitobj) - current_time) / self.preempt) * 3 + 1)
        p = hitobj.position
        r = self.scaled_number(self.hitcircle_radius * scale)

        pen = PEN_WHITE

        if self.can_access_judgments:
            judgment = self.hitobj_to_judgments[self.get_hit_time(hitobj)]
            if judgment.type is JudgmentType.Miss:
                # hitobj was missed, tint red
                pen = PEN_RED_TINT

        pen.setWidth(self.scaled_number(WIDTH_CIRCLE_BORDER / 2))
        self.painter.setPen(pen)
        self.painter.setOpacity(opacity)
        self.painter.drawEllipse(self.scaled_point(p.x, p.y), r, r)

    def draw_slider(self, hitobj):
        """
        Draws sliderbody, hitcircle, approachcircle if needed
        """
        self.draw_sliderbody(hitobj)
        self.draw_hitcircle(hitobj)
        self.draw_approachcircle(hitobj)

    def draw_sliderbody(self, hitobj):
        """
        Draws the sliderbody of a slider using a QpainterPath.
        """

        current_time = self.clock.get_time()
        fade_out = max(0, ((current_time - self.get_hit_endtime(hitobj)) / self.hitwindow_50))
        opacity = min(1, ((current_time - (self.get_hit_time(hitobj) - self.preempt)) / self.fade_in))
        opacity = max(0, min(1, opacity-fade_out)) * 0.75
        p = hitobj.position

        PEN_GRAY.setWidth(self.scaled_number(self.hitcircle_radius * 2))
        PEN_GRAY.setCapStyle(Qt.RoundCap)
        PEN_GRAY.setJoinStyle(Qt.RoundJoin)
        self.painter.setPen(PEN_GRAY)
        self.painter.setOpacity(opacity)

        sliderbody = QPainterPath()
        sliderbody.moveTo(self.scaled_point(p.x, p.y))
        for i in hitobj.slider_body:
            sliderbody.lineTo(self.scaled_point(i.x, i.y))
        self.painter.drawPath(sliderbody)

    def draw_hit_error_bar(self):
        mid_x = GAMEPLAY_WIDTH / 2
        y = GAMEPLAY_HEIGHT - ERROR_BAR_HIT_HEIGHT

        # draw the center white bar
        self.painter.setPen(PEN_WHITE)
        pen = self.painter.pen()
        pen.setWidth(ERROR_BAR_HIT_WIDTH)
        self.painter.setPen(pen)
        self.draw_line(1, [mid_x, y - ERROR_BAR_HIT_HEIGHT],
            [mid_x, y + ERROR_BAR_HIT_HEIGHT])

        # draw the three error zones as slightly transparent
        self.painter.setOpacity(0.65)
        self.painter.setPen(PEN_BLANK)

        hw300 = self.hitwindow_300 * self.error_bar_width_factor
        hw100 = self.hitwindow_100 * self.error_bar_width_factor
        hw50 = self.hitwindow_50 * self.error_bar_width_factor

        self.painter.setBrush(BRUSH_BLUE)
        p1 = self.scaled_point(mid_x - hw300, y - ERROR_BAR_HEIGHT)
        p2 = self.scaled_point(mid_x + hw300, y + ERROR_BAR_HEIGHT)
        self.painter.drawRect(QRectF(p1, p2))

        # draw two rects to avoid overlapping with hitwindow_300 in the center
        self.painter.setBrush(BRUSH_GREEN)
        p1 = self.scaled_point(mid_x - hw100, y - ERROR_BAR_HEIGHT)
        p2 = self.scaled_point(mid_x - hw300, y + ERROR_BAR_HEIGHT)
        self.painter.drawRect(QRectF(p1, p2))
        p1 = self.scaled_point(mid_x + hw300, y - ERROR_BAR_HEIGHT)
        p2 = self.scaled_point(mid_x + hw100, y + ERROR_BAR_HEIGHT)
        self.painter.drawRect(QRectF(p1, p2))

        self.painter.setBrush(BRUSH_YELLOW)
        p1 = self.scaled_point(mid_x - hw50, y - ERROR_BAR_HEIGHT)
        p2 = self.scaled_point(mid_x - hw100, y + ERROR_BAR_HEIGHT)
        self.painter.drawRect(QRectF(p1, p2))
        p1 = self.scaled_point(mid_x + hw100, y - ERROR_BAR_HEIGHT)
        p2 = self.scaled_point(mid_x + hw50, y + ERROR_BAR_HEIGHT)
        self.painter.drawRect(QRectF(p1, p2))

        self.painter.setBrush(BRUSH_BLANK)
        self.painter.setOpacity(1)

    def draw_hit(self, hitobj, hit):
        # TODO: avoid duplication in these constants between this and
        # `draw_hit_error_bar` - maybe just extract to globals?
        mid_x = GAMEPLAY_WIDTH / 2
        y = GAMEPLAY_HEIGHT - ERROR_BAR_HIT_HEIGHT

        if hit.type is JudgmentType.Hit300:
            pen = PEN_BLUE
        elif hit.type is JudgmentType.Hit100:
            pen = PEN_GREEN
        elif hit.type is JudgmentType.Hit50:
            pen = PEN_YELLOW

        self.painter.setPen(pen)
        pen = self.painter.pen()
        pen.setWidth(ERROR_BAR_HIT_WIDTH)
        self.painter.setPen(pen)

        current_time = self.clock.get_time()

        # positive is a late hit, negative is an early hit
        error = (hit.t - self.get_hit_time(hitobj)) * self.error_bar_width_factor
        start = [mid_x + error, y - ERROR_BAR_HIT_HEIGHT]
        end = [mid_x + error, y + ERROR_BAR_HIT_HEIGHT]

        time_passed = current_time - hit.t
        # how long in ms to display hits for before they disappear
        time_passed = min(time_passed, ERROR_BAR_HIT_THRESHOLD)
        # draw most recent hits as more visible (higher alpha) and old hits
        # as less visible (lower alpha)
        x_interp = [0, ERROR_BAR_HIT_THRESHOLD]
        y_interp = [1, 0]
        f = interpolate.interp1d(x_interp, y_interp)
        alpha = f(time_passed)
        self.draw_line(alpha, start, end)

    def draw_judgment_indicator(self, hitobj, judgment):
        if judgment.type is JudgmentType.Hit300:
            # don't draw anything for 300s
            return

        if judgment.type is JudgmentType.Miss:
            brush = BRUSH_JUDGMENT_MISS
            judgment_t = judgment.hitobject.time
        else:
            judgment_t = judgment.time
        if judgment.type is JudgmentType.Hit50:
            brush = BRUSH_JUDGMENT_50
        if judgment.type is JudgmentType.Hit100:
            brush = BRUSH_JUDGMENT_100

        self.painter.setPen(PEN_BLANK)
        self.painter.setBrush(brush)

        current_time = self.clock.get_time()

        time_passed = current_time - judgment_t
        time_passed = min(time_passed, JUDGMENT_INDICATOR_THRESHOLD)
        x_interp = [0, JUDGMENT_INDICATOR_THRESHOLD]
        y_interp = [1, 0]
        f = interpolate.interp1d(x_interp, y_interp)
        alpha = f(time_passed)

        self.painter.setOpacity(alpha)

        p = hitobj.position
        r = self.scaled_number(JUDGMENT_INDICATOR_RADIUS)
        self.painter.drawEllipse(self.scaled_point(p.x, p.y), r, r)

    def draw_progressbar(self, percentage):
        loading_bg = QPainterPath()
        loading_bar = QPainterPath()
        c = self.painter.pen().color()

        _pen = self.painter.pen()
        _pen.setWidth(5)
        _pen.setCapStyle(Qt.RoundCap)
        _pen.setJoinStyle(Qt.RoundJoin)
        _pen.setColor(QColor(c.red(), c.green(), c.blue(), 25))
        self.painter.setPen(_pen)

        loading_bg.moveTo(self.width()/2 - 75, self.height() / 2)
        loading_bg.lineTo(self.width()/2 - 75 + 150, self.height() / 2)

        loading_bar.moveTo(self.width() / 2 - 75, self.height() / 2)
        loading_bar.lineTo(self.width() / 2 - 75 + percentage * 1.5,
            self.height() / 2)

        self.painter.drawPath(loading_bg)
        _pen.setColor(QColor(c.red(), c.green(), c.blue(), 255))
        self.painter.setPen(_pen)
        self.painter.drawPath(loading_bar)

    def draw_loading_screen(self):
        x = self.width() / 2 - 75
        y = self.height() / 2 - 10
        self.painter.drawText(x, y, "Calculating Sliders, please wait...")
        progress = int((self.sliders_current / self.num_sliders) * 100)
        self.draw_progressbar(progress)

    def process_sliders(self):
        for i, hitobj in enumerate(self.hit_objects):
            self.sliders_current = i
            if isinstance(hitobj, Slider):
                steps = max(2, int((self.get_hit_endtime(hitobj) - self.get_hit_time(hitobj)) / SLIDER_TICKRATE))
                hitobj.slider_body = [hitobj.curve(i / steps) for i in range(steps + 1)]

    def search_nearest_frame(self, reverse=False):
        """
        Args
            Boolean reverse: whether to search backwards or forwards through
                time
        """
        if not reverse:
            next_frames = []
            for player in self.players:
                pos = player.end_pos + 1
                # stay at the end of the replay, avoid index error
                if pos == len(player.xy):
                    pos -= 1
                next_frames.append(player.t[pos])
            # if we're only visualizing a beatmap and there's no replays, and
            # someone tries to advance or retreat frames, min() / max() will
            # crash because next_frames is empty, so avoid this.
            if not next_frames:
                return
            self.seek_to(min(next_frames))
        else:
            prev_frames = []
            for player in self.players:
                pos = player.end_pos - 1
                # stay at the beginning of the replay, don't wrap around to end
                if pos == -1:
                    pos += 1
                prev_frames.append(player.t[pos])
            if not prev_frames:
                return
            self.seek_to(max(prev_frames), seeking_backwards=True)

    def seek_to(self, position, seeking_backwards=False):
        """
        Seeks to position if the change is bigger than ± 10.
        Also calls next_frame() so the correct frame is displayed.

        Args:
            Integer position: position to seek to in ms
            Boolean seeking_backwards: Whether we're seeking to a time before
                our current time.
        """
        self.clock.time_counter = position
        # if we want to seek somewhere while we're loading sliders, we store
        # that position so we can seek to it when loaded
        if self.is_loading:
            self.seek_to_when_loaded = position
        if self.paused:
            self.next_frame(stepping_backwards=seeking_backwards)

    def wheelEvent(self, event):
        # from the qt docs on pixelDelta: "This value is provided on platforms
        # that support high-resolution pixel-based delta values, such as macOS".
        # Since not every OS provides pixelDelta, we should use it if possible
        # but fall back to angleDelta. From my testing (sample size 1)
        # pixelDelta will have both x and y as zero if it's unsupported.
        if event.pixelDelta().x() == 0 and event.pixelDelta().y() == 0:
            # check both x and y to support users scrolling either vertically or
            # horizontally to move the timeline, just respect whichever is
            # greatest for that event.
            # this /5 is an arbitrary value to slow down scrolling to what
            # feels reasonable. TODO expose as a setting to the user ("scrolling
            # sensitivity")
            delta = max(event.angleDelta().x(), event.angleDelta().y(), key=abs) / 5
        else:
            delta = max(event.angleDelta().x(), event.angleDelta().y(), key=abs)

        self.seek_to(self.clock.time_counter + delta)

    def mouseMoveEvent(self, event):
        any_inside = False
        for rect in self.player_info_positions:
            qrect = rect.toQRect()
            if qrect.contains(event.pos()):
                any_inside = True
                self.setCursor(QCursor(Qt.PointingHandCursor))
        if not any_inside:
            self.setCursor(QCursor(Qt.ArrowCursor))
        return super().mouseMoveEvent(event)

    def mousePressEvent(self, event):
        for rect in self.player_info_positions:
            qrect = rect.toQRect()
            if qrect.contains(event.pos()):
                player = self.player_info_positions[rect]
                # toggle its membership in disabled_players, so users can click
                # a second time to re-enable a player
                if player in self.disabled_players:
                    self.disabled_players.remove(player)
                else:
                    self.disabled_players.append(player)
                self.update()
        return super().mousePressEvent(event)

    def get_hit_endtime(self, hitobj):
        if isinstance(hitobj, Circle):
            return self.get_hit_time(hitobj)
        t = hitobj.end_time.total_seconds() * 1000
        return int(round(t))

    def get_hit_time(self, hitobj):
        t = hitobj.time.total_seconds() * 1000
        # Due to floating point errors, ``t`` could actually be something
        # like ``129824.99999999999`` or ``128705.00000000001``, so round to the
        # nearest int.
        return int(round(t))

    def pause(self):
        """
        Set paused flag and pauses the clock.
        """
        self.paused = True
        self.clock.pause()

    def resume(self):
        """
        Removes paused flag and resumes the clock.
        """
        self.paused = False
        self.clock.resume()

    def toggle_frametime(self):
        self.paint_frametime = not self.paint_frametime

    def distance_between(self, point, hitobject):
        """
        The shortest distance between the given point and hitobject.
        """
        # TODO use numpy for these calculations
        x1 = point[0]
        y1 = point[1]
        x2 = hitobject.position.x
        y2 = hitobject.position.y
        r = self.hitcircle_radius
        return math.sqrt((((x2 - x1) ** 2) + (y2 - y1) ** 2)) - r

    def raw_view_changed(self, new_state):
        self.raw_view = new_state
        # redraw everything for the new raw view
        self.update()

    def only_color_keydowns_changed(self, new_state):
        self.only_color_keydowns = new_state
        self.update()

    def hitobjects_changed(self, new_state):
        self.draw_hitobjects = new_state
        self.update()

    def approach_circles_changed(self, new_state):
        self.draw_approach_circles = new_state
        self.update()

    def num_frames_changed(self, new_value):
        self.num_frames_on_screen = new_value
        self.update()

    def draw_hit_error_bar_changed(self, new_value):
        self.should_draw_hit_error_bar = new_value
        self.update()

    def circle_size_mod_changed(self, new_value):
        if not self.has_beatmap:
            # cs doesn't matter to us if we don't have a beatmap (and we don't
            # have the attributes necessary to compute it anyway)
            return
        use_hr = new_value == "HR"
        use_ez = new_value == "EZ"
        cs = self.beatmap.cs(hard_rock=use_hr, easy=use_ez)
        self.hitcircle_radius = hitradius(cs)
        self.update()
示例#53
0
 def paint(self, painter: QPainter,
                 option: QStyleOptionGraphicsItem,
                 widget: QWidget):
     painter.setPen(self.pen())
     painter.setBrush(self.brush())
     painter.drawPath(self.path())
示例#54
0
 def paint(self,
           painter: QtGui.QPainter,
           option: 'QStyleOptionGraphicsItem',
           widget: typing.Optional[QWidget] = ...) -> None:
     painter.setPen(self.current_color)
     painter.drawPath(self.path())
示例#55
0
    def paintEvent(self, event):
        if self.minimum() == self.maximum() == 0:
            return
        # 正弦曲线公式 y = A * sin(ωx + φ) + k
        # 当前值所占百分比
        percent = 1 - (self.value() - self.minimum()) / \
            (self.maximum() - self.minimum())
        # w表示周期,6为人为定义
        w = 6 * self.waterDensity * math.pi / self.width()
        # A振幅 高度百分比,1/26为人为定义
        A = self.height() * self.waterHeight * 1 / 26
        # k 高度百分比
        k = self.height() * percent

        # 波浪1
        waterPath1 = QPainterPath()
        waterPath1.moveTo(0, self.height())  # 起点在左下角
        # 波浪2
        waterPath2 = QPainterPath()
        waterPath2.moveTo(0, self.height())  # 起点在左下角

        # 偏移
        self._offset += 0.6
        if self._offset > self.width() / 2:
            self._offset = 0

        for i in range(self.width() + 1):
            # 从x轴开始计算y轴点
            y = A * math.sin(w * i + self._offset) + k
            waterPath1.lineTo(i, y)

            # 相对第一条需要进行错位
            y = A * math.sin(w * i + self._offset + self.width() / 2 * A) + k
            waterPath2.lineTo(i, y)

        # 封闭两条波浪,形成一个 U形 上面加波浪的封闭区间
        waterPath1.lineTo(self.width(), self.height())
        waterPath1.lineTo(0, self.height())
        waterPath2.lineTo(self.width(), self.height())
        waterPath2.lineTo(0, self.height())

        # 整体形状(矩形或者圆形)
        bgPath = QPainterPath()
        if self.styleType:
            bgPath.addRect(QRectF(self.rect()))
        else:
            radius = min(self.width(), self.height())
            bgPath.addRoundedRect(QRectF(self.rect()), radius, radius)

        # 开始画路径
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing, True)
        # 设置没有画笔
        painter.setPen(Qt.NoPen)

        if not self.styleType:
            # 圆形
            painter.setClipPath(bgPath)

        # 先整体绘制背景,然后再在背景上方绘制两条波浪
        painter.save()
        painter.setBrush(self.backgroundColor)
        painter.drawPath(bgPath)
        painter.restore()

        # 波浪1
        painter.save()
        painter.setBrush(self.waterColor1)
        painter.drawPath(waterPath1)
        painter.restore()

        # 波浪2
        painter.save()
        painter.setBrush(self.waterColor2)
        painter.drawPath(waterPath2)
        painter.restore()

        # 绘制文字
        if not self.isTextVisible():
            return
        painter.setPen(self.textColor)
        font = self.font() or QFont()
        font.setPixelSize(int(min(self.width(), self.height()) / 2))
        painter.setFont(font)
        painter.drawText(self.rect(), Qt.AlignCenter, '%d%%' %
                         (self.value() / self.maximum() * 100))
示例#56
0
    def paintEvent(self, pe):
        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing)

        pen = QPen()
        pen.setWidth(1)
        pen.setColor(QColor(0x8c, 0xa3, 0xb0))
        p.setPen(pen)

        p.setBrush(QColor(0xe4, 0xec, 0xf4))

        rx = 6

        space = self.space
        w = self.usable_width
        kw = self.key_w

        def drawRow(row, sx, sy, last_end=False):
            x = sx
            y = sy
            keys = row
            rw = w - sx
            i = 0
            for k in keys:
                rect = QRectF(x, y, kw, kw)

                if i == len(keys) - 1 and last_end:
                    rect.setWidth(rw)

                p.drawRoundedRect(rect, rx, rx)
                p.setPen(Qt.black)

                rect.adjust(5, 1, 0, 0)

                p.setFont(self.lowerFont)
                p.drawText(
                    rect, Qt.AlignLeft | Qt.AlignBottom, self.regular_text(k))

                p.setFont(self.upperFont)
                p.drawText(
                    rect, Qt.AlignLeft | Qt.AlignTop, self.shift_text(k))

                rw = rw - space - kw
                x = x + space + kw
                i = i + 1

                p.setPen(pen)
            return (x, rw)

        x = .5
        y = .5

        keys = self.kb["keys"]
        ext_return = self.kb["extended_return"]

        first_key_w = 0

        rows = 4
        remaining_x = [0, 0, 0, 0]
        remaining_widths = [0, 0, 0, 0]

        for i in range(0, rows):
            if first_key_w > 0:
                first_key_w = first_key_w * 1.375

                if self.kb == self.kb_105 and i == 3:
                    first_key_w = kw * 1.275

                rect = QRectF(x, y, first_key_w, kw)
                p.drawRoundedRect(rect, rx, rx)
                x = x + first_key_w + space
            else:
                first_key_w = kw

            x, rw = drawRow(keys[i], x, y, i == 1 and not ext_return)

            remaining_x[i] = x
            remaining_widths[i] = rw

            if i != 1 and i != 2:
                rect = QRectF(x, y, rw, kw)
                p.drawRoundedRect(rect, rx, rx)

            x = .5
            y = y + space + kw

        if ext_return:
            rx = rx * 2
            x1 = remaining_x[1]
            y1 = .5 + kw * 1 + space * 1
            w1 = remaining_widths[1]
            x2 = remaining_x[2]
            y2 = .5 + kw * 2 + space * 2

            # this is some serious crap... but it has to be so
            # maybe one day keyboards won't look like this...
            # one can only hope
            pp = QPainterPath()
            pp.moveTo(x1, y1 + rx)
            pp.arcTo(x1, y1, rx, rx, 180, -90)
            pp.lineTo(x1 + w1 - rx, y1)
            pp.arcTo(x1 + w1 - rx, y1, rx, rx, 90, -90)
            pp.lineTo(x1 + w1, y2 + kw - rx)
            pp.arcTo(x1 + w1 - rx, y2 + kw - rx, rx, rx, 0, -90)
            pp.lineTo(x2 + rx, y2 + kw)
            pp.arcTo(x2, y2 + kw - rx, rx, rx, -90, -90)
            pp.lineTo(x2, y1 + kw)
            pp.lineTo(x1 + rx, y1 + kw)
            pp.arcTo(x1, y1 + kw - rx, rx, rx, -90, -90)
            pp.closeSubpath()

            p.drawPath(pp)
        else:
            x = remaining_x[2]
            y = .5 + kw * 2 + space * 2
            rect = QRectF(x, y, remaining_widths[2], kw)
            p.drawRoundedRect(rect, rx, rx)

        QWidget.paintEvent(self, pe)
示例#57
0
class BaseChartPicGenerator(ABC):
    LANE_DISTANCE = LANE_DISTANCE
    SKILL_PAINT_WIDTH = SKILL_PAINT_WIDTH

    unit = None

    def __init__(self,
                 song_id,
                 difficulty,
                 main_window,
                 grand,
                 reset_main=True,
                 mirrored=False):
        self.song_id = song_id
        self.difficulty = difficulty
        self.main = main_window
        self.grand = grand
        if grand:
            self.lane_count = 15
        else:
            self.lane_count = 5

        self.notes = fetch_chart(None,
                                 song_id,
                                 difficulty,
                                 event=False,
                                 skip_load_notes=False)[0]
        if self.notes is None:
            self.notes = fetch_chart(None,
                                     song_id,
                                     difficulty,
                                     event=True,
                                     skip_load_notes=False)[0]
        self.notes['finishPos'] -= 1
        self.mirrored = mirrored
        if mirrored:
            if not grand:
                self.notes['finishPos'] = 4 - self.notes['finishPos']
            else:
                self.notes['finishPos'] = 15 - (self.notes['finishPos'] +
                                                self.notes['status'])
        self.notes_into_group()
        self.generate_note_objects()

        self.initialize_ui()
        if reset_main:
            self.main.setGeometry(200, 200, self.x_max, self.y_max)

        self.p = QPainter(self.label.pixmap())
        self.p.setRenderHint(QPainter.Antialiasing)
        self.draw()
        self.label.repaint()

    def mirror_generator(self, mirrored):
        if self.mirrored == mirrored:
            return self
        return BaseChartPicGenerator.get_generator(self.song_id,
                                                   self.difficulty,
                                                   self.main,
                                                   reset_main=False,
                                                   mirrored=mirrored)

    @classmethod
    def get_generator(cls,
                      song_id,
                      difficulty,
                      main_window,
                      reset_main=True,
                      mirrored=False):
        if isinstance(difficulty, int):
            difficulty = Difficulty(difficulty)
        if difficulty == Difficulty.PIANO or difficulty == Difficulty.FORTE:
            return GrandChartPicGenerator(song_id, difficulty, main_window,
                                          True, reset_main, mirrored)
        else:
            return BasicChartPicGenerator(song_id, difficulty, main_window,
                                          False, reset_main, mirrored)

    def notes_into_group(self):
        long_groups = list()
        long_stack = defaultdict(lambda: list())
        for _, note in self.notes.iterrows():
            # Handle long differently
            lane = note['finishPos']
            if note['note_type'] == NoteType.LONG and lane not in long_stack:
                long_stack[lane].append((_, note))
            elif lane in long_stack:
                long_stack[lane].append((_, note))
                long_groups.append(long_stack.pop(lane))
        long_dummy_group = 2000
        for pair in long_groups:
            group_id = max(pair[0][1]['groupId'], pair[1][1]['groupId'])
            if group_id == 0:
                group_id = long_dummy_group
                long_dummy_group += 1
            self.notes.loc[pair[0][0], 'groupId'] = group_id
            self.notes.loc[pair[1][0], 'groupId'] = group_id

    def initialize_ui(self):
        self.y_total = MAX_SECS_PER_GROUP * SEC_HEIGHT + 2 * Y_MARGIN
        self.x_total = (2 * X_MARGIN + (self.lane_count - 1) *
                        self.LANE_DISTANCE) * self.n_groups + RIGHT_MARGIN

        self.label = QLabel()
        self.label.setAlignment(Qt.AlignBottom)
        self.label.setFixedSize(self.x_total, self.y_total)

        canvas = QPixmap(self.x_total, self.y_total)
        self.label.setPixmap(canvas)

        scroll = DraggableQScrollArea()
        scroll.setWidget(self.label)
        # Scroll to bottom
        vbar = scroll.verticalScrollBar()
        vbar.setValue(vbar.maximum())
        self.main.setCentralWidget(scroll)
        self.y_max = WINDOW_HEIGHT
        self.x_max = min(MAX_WINDOW_WIDTH, self.x_total + 20)

    def get_x(self, lane, group):
        return X_MARGIN + lane * self.LANE_DISTANCE + (
            2 * X_MARGIN + (self.lane_count - 1) * self.LANE_DISTANCE) * group

    def get_y(self, sec, group=None, offset_group=0):
        if group is not None:
            return self.y_total - Y_MARGIN - (
                sec - group * MAX_SECS_PER_GROUP) * SEC_HEIGHT
        else:
            return self.y_total - Y_MARGIN - (
                sec - (sec // MAX_SECS_PER_GROUP + offset_group) *
                MAX_SECS_PER_GROUP) * SEC_HEIGHT

    # Lanes start from 0
    def generate_note_objects(self, abuse_df=None):
        # Number of groups = ceil(last sec // MAX_SECS_PER_GROUP)
        self.last_sec = int(self.notes.sec.iloc[-1]) + 1
        self.n_groups = ceil(self.last_sec / MAX_SECS_PER_GROUP)
        self.note_groups = list()
        for n in range(self.n_groups):
            group = list()
            df_slice = self.notes[
                (n * MAX_SECS_PER_GROUP -
                 Y_MARGIN / SEC_HEIGHT <= self.notes['sec'])
                & (self.notes['sec'] <=
                   (n + 1) * MAX_SECS_PER_GROUP + Y_MARGIN / SEC_HEIGHT)]
            for _, row in df_slice.iterrows():
                right_flick = row['note_type'] == NoteType.FLICK and (
                    row['status'] == 2 and not self.grand) or (row['type'] == 7
                                                               and self.grand)
                if self.mirrored:
                    right_flick = not right_flick
                if abuse_df is not None and _ in abuse_df.index:
                    delta = abuse_df.loc[_, 'delta']
                    early = abuse_df.loc[_, 'abuse_range_l']
                    late = abuse_df.loc[_, 'abuse_range_r']
                    great = abuse_df.loc[_, 'is_great']
                else:
                    delta = 0
                    early = 0
                    late = 0
                    great = False
                note_object = ChartPicNote(sec=row['sec'],
                                           note_type=row['note_type'],
                                           lane=row['finishPos'],
                                           sync=row['sync'],
                                           qgroup=n,
                                           group_id=row['groupId'],
                                           delta=delta,
                                           early=early,
                                           late=late,
                                           right_flick=right_flick,
                                           grand=self.grand,
                                           span=row['status'] -
                                           1 if self.grand else 0,
                                           great=great)
                group.append(note_object)
            self.note_groups.append(group)

    def draw(self):
        self.draw_grid_and_secs()
        self.draw_sync_lines()
        self.draw_group_lines()
        self.draw_notes()

    def hook_cards(self, all_cards, redraw=True):
        try:
            if len(all_cards) == 15:
                unit = GrandUnit.from_list(all_cards)
            else:
                unit = Unit.from_list(cards=all_cards[:5])
        except InvalidUnit:
            return
        # Skip drawing if same unit else reset drawing
        if not self.grand and isinstance(unit, GrandUnit):
            unit = unit.ua
        if unit == self.unit:
            return
        self.p.fillRect(0, 0, self.x_total, self.y_total, Qt.black)
        self.unit = unit
        self.paint_skill()
        self.draw()
        if redraw:
            self.label.repaint()

    def paint_skill(self):
        for card_idx, card in enumerate(self.unit.all_cards()):
            skill = card.sk
            interval = skill.interval
            duration = skill.duration
            skill_times = int((self.last_sec - 3) // interval)
            skill_time = 1
            group = 0
            while group < self.n_groups:
                left = skill_time * interval
                right = skill_time * interval + duration
                #  Do not paint if skill entirely outside group
                if left > (group +
                           1) * MAX_SECS_PER_GROUP + Y_MARGIN / SEC_HEIGHT:
                    group += 1
                    skill_time -= 1
                    continue
                if self.grand and (skill_time - 1) % 3 != skill.offset:
                    skill_time += 1
                    continue
                if skill_time > skill_times:
                    break
                skill_brush = QBrush(
                    QColor(*SKILL_BASE[skill.skill_type]['color'], 100))
                self.p.setPen(QPen())
                self.p.setBrush(skill_brush)
                # Need to convert grand lane
                draw_card_idx = card_idx
                if self.grand:
                    if card_idx < 5:
                        draw_card_idx += 5
                    elif 5 <= card_idx < 10:
                        draw_card_idx -= 5
                x = self.get_x(draw_card_idx, group)
                y = self.get_y(right, group)
                self.p.drawRect(x - self.SKILL_PAINT_WIDTH // 2, y,
                                self.SKILL_PAINT_WIDTH, duration * SEC_HEIGHT)
                skill_time += 1

    def draw_grid_and_secs(self):
        font = QFont()
        font.setPixelSize(36)
        self.p.setFont(font)

        vertical_grid_pen = QPen(QColor(80, 80, 80))
        vertical_grid_pen.setWidth(5)
        self.p.setPen(vertical_grid_pen)
        for group in range(self.n_groups):
            for lane in range(self.lane_count):
                x = self.get_x(lane, group)
                self.p.drawLine(x, 0, x, self.y_total)

        horizontal_grid_bold_pen = QPen(QColor(120, 120, 120))
        horizontal_grid_bold_pen.setWidth(5)
        horizontal_grid_light_pen = QPen(QColor(80, 80, 80))
        horizontal_grid_light_pen.setWidth(3)
        for group in range(self.n_groups):
            for sec in range(MAX_SECS_PER_GROUP + 1):
                if (sec + group * MAX_SECS_PER_GROUP) % 5 == 0:
                    self.p.setPen(horizontal_grid_bold_pen)
                else:
                    self.p.setPen(horizontal_grid_light_pen)
                y = self.get_y(sec, group=0)
                self.p.drawLine(self.get_x(0, group), y,
                                self.get_x(self.lane_count - 1, group), y)
                self.p.drawText(
                    QRect(self.get_x(0, group) - 111, y - 25, 70, 50),
                    Qt.AlignRight, str(sec + MAX_SECS_PER_GROUP * group))

    @abstractmethod
    def draw_notes(self):
        pass

    def _is_double_drawn_note(self, note: ChartPicNote):
        for _ in range(self.n_groups):
            if MAX_SECS_PER_GROUP * _ - Y_MARGIN / SEC_HEIGHT <= note.sec <= MAX_SECS_PER_GROUP * _ + Y_MARGIN / SEC_HEIGHT:
                return True
        return False

    def draw_sync_lines(self):
        sync_line_pen = QPen(QColor(250, 250, 240))
        sync_line_pen.setWidth(3)
        self.p.setPen(sync_line_pen)
        for group_idx, qt_group in enumerate(self.note_groups):
            sync_pairs = defaultdict(lambda: list())
            for note in qt_group:
                if note.sync == 0:
                    continue
                sync_pairs[note.sec].append(note)
            for values in sync_pairs.values():
                l = min(values[0].lane, values[1].lane)
                r = max(values[0].lane, values[1].lane)
                sec = values[0].sec
                y = self.get_y(sec, group_idx)
                self.p.drawLine(self.get_x(l, group_idx), y,
                                self.get_x(r, group_idx), y)

    @abstractmethod
    def _draw_group_line(self, note1, note2, group):
        pass

    def draw_group_lines(self):
        for group_idx, qt_group in enumerate(self.note_groups):
            group_ids = set()
            for note in qt_group:
                if note.group_id == 0:
                    continue
                group_ids.add(note.group_id)
            grouped_notes_df = self.notes[self.notes['groupId'].isin(
                group_ids)]
            for group_id, grouped_notes in grouped_notes_df.groupby("groupId"):
                for l, r in zip(grouped_notes.iloc[1:].T.to_dict().values(),
                                grouped_notes.iloc[:-1].T.to_dict().values()):
                    self._draw_group_line(l, r, group_idx)

    def hook_abuse(self, all_cards, abuse_df):
        self.hook_cards(all_cards, False)

        self.generate_note_objects(abuse_df)
        for group_idx, qt_group in enumerate(self.note_groups):
            for note in qt_group:
                self.draw_abuse(note, group_idx)
        self.label.repaint()

    def draw_abuse(self, note: ChartPicNote, group):
        if note.delta == 0:
            return

        x_note = self.get_x(note.lane + note.span / 2,
                            group) - note.note_pic_smol.width() // 2
        y_early = self.get_y(note.sec + note.early / 1000, group)
        shifted_y_early = y_early - note.note_pic_smol.height() // 2
        y_late = self.get_y(note.sec + note.late / 1000, group)
        shifted_y_late = y_late - note.note_pic_smol.height() // 2
        self.p.drawImage(QPoint(x_note, shifted_y_early), note.note_pic_smol)
        self.p.drawImage(QPoint(x_note, shifted_y_late), note.note_pic_smol)
        lane_l = self.get_x(0, group)
        lane_r = self.get_x(self.lane_count - 1, group)
        self.p.setPen(QPen(Qt.green))
        self.p.drawLine(lane_l, y_early, lane_r, y_early)
        self.p.setPen(QPen(Qt.red))
        self.p.drawLine(lane_l, y_late, lane_r, y_late)

        x = self.get_x(note.lane + note.span / 2,
                       group) - note.note_pic.width() // 2
        y = self.get_y(note.sec, group) + note.note_pic.height()
        font = QFont()
        font.setBold(True)
        font.setPixelSize(30)
        pen = QPen()
        pen.setWidth(1)
        pen.setColor(Qt.white)
        if note.great:
            brush = QBrush(QColor(66, 13, 110))
        else:
            brush = QBrush(Qt.black)
        path = QPainterPath()
        path.addText(x, y, font, str(note.delta))
        self.p.setFont(font)
        self.p.setPen(pen)
        self.p.setBrush(brush)
        self.p.drawPath(path)
        font.setPixelSize(24)
        path = QPainterPath()
        path.addText(x, y + 40, font, "{} {}".format(note.early, note.late))
        self.p.drawPath(path)

    def save_image(self):
        self.label.pixmap().save("{}-{}.png".format(self.song_id,
                                                    self.difficulty))
示例#58
0
    def createArrowBackground(self, transform):
        scaledRect = transform.mapRect(QRect(0, 0,
                self.logicalSize.width(), self.logicalSize.height()))

        image = QImage(scaledRect.width(), scaledRect.height(),
                QImage.Format_ARGB32_Premultiplied)
        image.fill(QColor(0, 0, 0, 0).rgba())
        painter = QPainter(image)
        painter.setRenderHint(QPainter.SmoothPixmapTransform)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setPen(Qt.NoPen)

        if Colors.useEightBitPalette:
            painter.setPen(QColor(120, 120, 120))
            if self.pressed:
                painter.setBrush(QColor(60, 60, 60))
            elif self.highlighted:
                painter.setBrush(QColor(100, 100, 100))
            else:
                painter.setBrush(QColor(80, 80, 80))
        else:
            outlinebrush = QLinearGradient(0, 0, 0, scaledRect.height())
            brush = QLinearGradient(0, 0, 0, scaledRect.height())

            brush.setSpread(QLinearGradient.PadSpread)
            highlight = QColor(255, 255, 255, 70)
            shadow = QColor(0, 0, 0, 70)
            sunken = QColor(220, 220, 220, 30)
            normal1 = QColor(200, 170, 160, 50)
            normal2 = QColor(50, 10, 0, 50)

            if self.pressed:
                outlinebrush.setColorAt(0, shadow)
                outlinebrush.setColorAt(1, highlight)
                brush.setColorAt(0, sunken)
                painter.setPen(Qt.NoPen)
            else:
                outlinebrush.setColorAt(1, shadow)
                outlinebrush.setColorAt(0, highlight)
                brush.setColorAt(0, normal1)
                if not self.highlighted:
                    brush.setColorAt(1, normal2)
                painter.setPen(QPen(outlinebrush, 1))

            painter.setBrush(brush);

        painter.drawRect(0, 0, scaledRect.width(), scaledRect.height())

        xOff = scaledRect.width() / 2
        yOff = scaledRect.height() / 2
        sizex = 3.0 * transform.m11()
        sizey = 1.5 * transform.m22()
        if self.type == TextButton.UP:
            sizey *= -1
        path = QPainterPath()
        path.moveTo(xOff, yOff + (5 * sizey))
        path.lineTo(xOff - (4 * sizex), yOff - (3 * sizey))
        path.lineTo(xOff + (4 * sizex), yOff - (3 * sizey))
        path.lineTo(xOff, yOff + (5 * sizey))
        painter.drawPath(path)

        return image
示例#59
0
    def paintEvent(self, event):
        painter = QPainter(self)
        visibleRect = event.rect()
        columnCount = self._columnCount
        extra = self._cellWidthExtra
        cellWidth, cellHeight = self._cellWidth + 2 * extra, self._cellHeight
        glyphCount = len(self._glyphs)
        if columnCount:
            paintWidth = min(glyphCount, columnCount) * cellWidth
        else:
            paintWidth = 0
        left = 0
        top = cellHeight

        painter.fillRect(visibleRect, Qt.white)
        for index, glyph in enumerate(self._glyphs):
            t = top - cellHeight
            rect = (left, t, cellWidth, cellHeight)

            if visibleRect.intersects(visibleRect.__class__(*rect)):
                if index in self._selection:
                    palette = self.palette()
                    active = palette.currentColorGroup() != QPalette.Inactive
                    opacityMultiplier = platformSpecific.colorOpacityMultiplier()
                    selectionColor = palette.color(QPalette.Highlight)
                    # TODO: alpha values somewhat arbitrary (here and in
                    # glyphLineView)
                    selectionColor.setAlphaF(
                        .2 * opacityMultiplier if active else .7)
                    painter.fillRect(QRectF(
                        left, t, cellWidth, cellHeight),
                        selectionColor)

                pixmap = self._getCurrentRepresentation(glyph)
                painter.drawPixmap(left, t, pixmap)

                # XXX: this hacks around the repr internals
                if index in self._selection and \
                        cellHeight >= GlyphCellMinHeightForHeader:
                    painter.fillRect(QRectF(
                        left, t + cellHeight - GlyphCellHeaderHeight,
                        cellWidth, GlyphCellHeaderHeight),
                        selectionColor)

            left += cellWidth
            if left + cellWidth > paintWidth:
                left = 0
                top += cellHeight

        # drop insertion position
        dropIndex = self._currentDropIndex
        if dropIndex is not None:
            if columnCount:
                x = (dropIndex % columnCount) * cellWidth
                y = (dropIndex // columnCount) * cellHeight
                # special-case the end-column
                if dropIndex == glyphCount and \
                        glyphCount < self.width() // self._cellWidth or \
                        self.mapFromGlobal(QCursor.pos()).y() < y:
                    x = columnCount * cellWidth
                    y -= cellHeight
            else:
                x = y = 0
            path = QPainterPath()
            path.addRect(x - 2, y, 3, cellHeight)
            path.addEllipse(x - 5, y - 5, 9, 9)
            path.addEllipse(x - 5, y + cellHeight - 5, 9, 9)
            path.setFillRule(Qt.WindingFill)
            pen = painter.pen()
            pen.setColor(Qt.white)
            pen.setWidth(2)
            painter.setPen(pen)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.drawPath(path)
            painter.fillPath(path, insertionPositionColor)