Ejemplo n.º 1
0
 def drawBackgroundToPixmap(self):
     r = self.sceneRect()
     self.background = QPixmap(qRound(r.width()), qRound(r.height()))
     self.background.fill(Qt.black)
     painter = QPainter(self.background)
     bg = QImage("%simg/BG.png" % (colors.SYSPATH))
     painter.drawImage(0, 0, bg)
Ejemplo n.º 2
0
    def paint(self, painter, option=None, widget=None):
        if self._validateImage():
            wasSmoothPixmapTransform = painter.testRenderHint(
                QPainter.SmoothPixmapTransform)
            painter.setRenderHint(QPainter.SmoothPixmapTransform)

            if Colors.noRescale:
                # Let the painter scale the image for us.  This may degrade
                # both quality and performance.
                if self._sharedImage.image is not None:
                    painter.drawImage(self.pos(), self._sharedImage.image)
                else:
                    painter.drawPixmap(self.pos(), self._sharedImage.pixmap)
            else:
                m = painter.worldTransform()
                painter.setWorldTransform(QTransform())

                x = m.dx()
                y = m.dy()
                if self.noSubPixeling:
                    x = qRound(x)
                    y = qRound(y)

                if self._sharedImage.image is not None:
                    painter.drawImage(QPointF(x, y), self._sharedImage.image)
                else:
                    painter.drawPixmap(QPointF(x, y), self._sharedImage.pixmap)

            if not wasSmoothPixmapTransform:
                painter.setRenderHint(QPainter.SmoothPixmapTransform, False)
Ejemplo n.º 3
0
    def paint(self, painter, option=None, widget=None):
        if self._validateImage():
            wasSmoothPixmapTransform = painter.testRenderHint(QPainter.SmoothPixmapTransform)
            painter.setRenderHint(QPainter.SmoothPixmapTransform)

            if Colors.noRescale:
                # Let the painter scale the image for us.  This may degrade
                # both quality and performance.
                if self._sharedImage.image is not None:
                    painter.drawImage(self.pos(), self._sharedImage.image)
                else:
                    painter.drawPixmap(self.pos(), self._sharedImage.pixmap)
            else:
                m = painter.worldTransform()
                painter.setWorldTransform(QTransform())

                x = m.dx()
                y = m.dy()
                if self.noSubPixeling:
                    x = qRound(x)
                    y = qRound(y)

                if self._sharedImage.image is not None:
                    painter.drawImage(QPointF(x, y), self._sharedImage.image)
                else:
                    painter.drawPixmap(QPointF(x, y), self._sharedImage.pixmap)

            if not wasSmoothPixmapTransform:
                painter.setRenderHint(QPainter.SmoothPixmapTransform,
                        False)
Ejemplo n.º 4
0
    def drawBackgroundToPixmap(self):
        r = self.scene.sceneRect()
        self.background = QPixmap(qRound(r.width()), qRound(r.height()))
        self.background.fill(Qt.black)
        painter = QPainter(self.background)

        bg = QImage(':/images/demobg.png')
        painter.drawImage(0, 0, bg)
Ejemplo n.º 5
0
 def drawScaleContents( self,  painter, double ):
     dir = 360 - qRound( self.origin() - self.value() ) # counter clockwise
     arc = 90 + qRound( self.gradient() * 90 )
     skyColor = QColor( 38, 151, 221 )
     painter.save()
     painter.setBrush( skyColor )
     painter.drawChord( self.scaleInnerRect(), ( dir - arc ) * 16, 2 * arc * 16 )
     painter.restore()
    def lineNumberAreaPaintEvent(self, event):
        painter = QPainter(self.lineNumberArea)
        painter.fillRect(event.rect(), QColor(69, 69, 69))
        block = self.firstVisibleBlock()
        blockNumber = block.blockNumber()
        top = qRound(self.blockBoundingGeometry(block).translated(self.contentOffset()).top())
        bottom = top + qRound(self.blockBoundingRect(block).height())
        while block.isValid() and top <= event.rect().bottom():
            if block.isVisible() and bottom >= event.rect().top():
                number = str(blockNumber + 1)
                painter.setPen(QColor(170, 170, 170))
                painter.drawText(0, top, self.lineNumberArea.width(), self.fontMetrics().height(),
                                 Qt.AlignRight, number + " ")

            block = block.next()
            top = bottom
            bottom = top + qRound(self.blockBoundingRect(block).height())
            blockNumber += 1
Ejemplo n.º 7
0
    def _paint_icon(self, iconic, painter, rect, mode, state, options):
        """Paint a single icon."""
        painter.save()
        color = options['color']
        char = options['char']

        color_options = {
            QIcon.On: {
                QIcon.Normal: (options['color_on'], options['on']),
                QIcon.Disabled: (options['color_on_disabled'],
                                 options['on_disabled']),
                QIcon.Active: (options['color_on_active'],
                               options['on_active']),
                QIcon.Selected: (options['color_on_selected'],
                                 options['on_selected'])
            },

            QIcon.Off: {
                QIcon.Normal: (options['color_off'], options['off']),
                QIcon.Disabled: (options['color_off_disabled'],
                                 options['off_disabled']),
                QIcon.Active: (options['color_off_active'],
                               options['off_active']),
                QIcon.Selected: (options['color_off_selected'],
                                 options['off_selected'])
            }
        }

        color, char = color_options[state][mode]

        painter.setPen(QColor(color))

        # A 16 pixel-high icon yields a font size of 14, which is pixel perfect
        # for font-awesome. 16 * 0.875 = 14
        # The reason why the glyph size is smaller than the icon size is to
        # account for font bearing.

        draw_size = 0.875 * qRound(rect.height() * options['scale_factor'])
        prefix = options['prefix']

        # Animation setup hook
        animation = options.get('animation')
        if animation is not None:
            animation.setup(self, painter, rect)

        painter.setFont(iconic.font(prefix, draw_size))
        if 'offset' in options:
            rect = QRect(rect)
            rect.translate(options['offset'][0] * rect.width(),
                           options['offset'][1] * rect.height())

        painter.setOpacity(options.get('opacity', 1.0))

        painter.drawText(rect, Qt.AlignCenter | Qt.AlignVCenter, char)
        painter.restore()
Ejemplo n.º 8
0
    def _paint_icon(self, iconic, painter, rect, mode, state, options):
        """Paint a single icon."""
        painter.save()
        color = options['color']
        char = options['char']

        color_options = {
            QIcon.On: {
                QIcon.Normal: (options['color_on'], options['on']),
                QIcon.Disabled:
                (options['color_on_disabled'], options['on_disabled']),
                QIcon.Active:
                (options['color_on_active'], options['on_active']),
                QIcon.Selected:
                (options['color_on_selected'], options['on_selected'])
            },
            QIcon.Off: {
                QIcon.Normal: (options['color_off'], options['off']),
                QIcon.Disabled:
                (options['color_off_disabled'], options['off_disabled']),
                QIcon.Active:
                (options['color_off_active'], options['off_active']),
                QIcon.Selected:
                (options['color_off_selected'], options['off_selected'])
            }
        }

        color, char = color_options[state][mode]

        painter.setPen(QColor(color))

        # A 16 pixel-high icon yields a font size of 14, which is pixel perfect
        # for font-awesome. 16 * 0.875 = 14
        # The reason why the glyph size is smaller than the icon size is to
        # account for font bearing.

        draw_size = 0.875 * qRound(rect.height() * options['scale_factor'])
        prefix = options['prefix']

        # Animation setup hook
        animation = options.get('animation')
        if animation is not None:
            animation.setup(self, painter, rect)

        painter.setFont(iconic.font(prefix, draw_size))
        if 'offset' in options:
            rect = QRect(rect)
            rect.translate(options['offset'][0] * rect.width(),
                           options['offset'][1] * rect.height())

        painter.setOpacity(options.get('opacity', 1.0))

        painter.drawText(rect, Qt.AlignCenter | Qt.AlignVCenter, char)
        painter.restore()
Ejemplo n.º 9
0
    def statusAreaPaintEvent(self, event: QPaintEvent):
        painter = QPainter(self._statusArea)
        painter.fillRect(event.rect(), Qt.lightGray)

        block = self.firstVisibleBlock()
        top = qRound(
            self.blockBoundingGeometry(block).translated(
                self.contentOffset()).top())
        bottom = top + qRound(self.blockBoundingRect(block).height())

        while block.isValid() and top <= event.rect().bottom():
            if block.isVisible() and bottom >= event.rect().top():
                painter.setPen(Qt.red)
                painter.drawText(
                    0,
                    top,
                    self._statusArea.width(),
                    self.fontMetrics().height(),
                    Qt.AlignRight,
                    MARK if block.userState() == self._State.Error else NOMARK,
                )
            block = block.next()
            top = bottom
            bottom = top + qRound(self.blockBoundingRect(block).height())
Ejemplo n.º 10
0
    def _paint_icon(self, iconic, painter, rect, mode, state, options):
        """Paint a single icon"""
        painter.save()
        color, char = options['color'], options['char']

        if mode == QIcon.Disabled:
            color = options.get('color_disabled', color)
            char = options.get('disabled', char)
        elif mode == QIcon.Active:
            color = options.get('color_active', color)
            char = options.get('active', char)
        elif mode == QIcon.Selected:
            color = options.get('color_selected', color)
            char = options.get('selected', char)

        painter.setPen(QColor(color))
        # A 16 pixel-high icon yields a font size of 14, which is pixel perfect
        # for font-awesome. 16 * 0.875 = 14
        # The reason for not using full-sized glyphs is the negative bearing of
        # fonts.
        draw_size = 0.875 * qRound(rect.height() * options['scale_factor'])
        prefix = options['prefix']

        # Animation setup hook
        animation = options.get('animation')
        if animation is not None:
            animation.setup(self, painter, rect)

        painter.setFont(iconic.font(prefix, draw_size))
        if 'offset' in options:
            rect = QRect(rect)
            rect.translate(options['offset'][0] * rect.width(),
                           options['offset'][1] * rect.height())

        painter.setOpacity(options.get('opacity', 1.0))

        painter.drawText(rect, Qt.AlignCenter | Qt.AlignVCenter, char)
        painter.restore()
Ejemplo n.º 11
0
    def _paint_icon(self, iconic, painter, rect, mode, state, options):
        """Paint a single icon"""
        painter.save()
        color, char = options['color'], options['char']

        if mode == QIcon.Disabled:
            color = options.get('color_disabled', color)
            char = options.get('disabled', char)
        elif mode == QIcon.Active:
            color = options.get('color_active', color)
            char = options.get('active', char)
        elif mode == QIcon.Selected:
            color = options.get('color_selected', color)
            char = options.get('selected', char)

        painter.setPen(QColor(color))
        # A 16 pixel-high icon yields a font size of 14, which is pixel perfect
        # for font-awesome. 16 * 0.875 = 14
        # The reason for not using full-sized glyphs is the negative bearing of
        # fonts.
        draw_size = 0.875 * qRound(rect.height() * options['scale_factor'])
        prefix = options['prefix']

        # Animation setup hook
        animation = options.get('animation')
        if animation is not None:
            animation.setup(self, painter, rect)

        painter.setFont(iconic.font(prefix, draw_size))
        if 'offset' in options:
            rect = QRect(rect)
            rect.translate(options['offset'][0] * rect.width(),
                           options['offset'][1] * rect.height())

        painter.setOpacity(options.get('opacity', 1.0))

        painter.drawText(rect, Qt.AlignCenter | Qt.AlignVCenter, char)
        painter.restore()
Ejemplo n.º 12
0
    def deliverEvent(self, event, texCoord):
        # Map the texture co-ordinate into "screen" co-ordinates.
        # Mouse move and release events can extend beyond the boundaries
        # of the scene, for "click and drag off-screen" operations.
        # Mouse press and double-click events need to be constrained.
        bounds = self.sceneRect()
        screenX = qRound(texCoord.x() * bounds.width())
        screenY = qRound((1.0 - texCoord.y()) * bounds.height())
        if event.type() in (QEvent.GraphicsSceneMousePress,
                            QEvent.GraphicsSceneMouseDoubleClick,
                            QEvent.MouseButtonPress,
                            QEvent.MouseButtonDblClick):
            if screenX < 0:
                screenX = 0
            elif screenX >= bounds.width():
                screenX = qRound(bounds.width() - 1)
            if screenY < 0:
                screenY = 0
            elif screenY >= bounds.height():
                screenY = qRound(bounds.height() - 1)
            self.pressedPos = QPoint(screenX, screenY)

        # Convert the event and deliver it to the scene.
        eventType = event.type()

        if eventType in (QEvent.GraphicsSceneMouseMove,
                         QEvent.GraphicsSceneMousePress,
                         QEvent.GraphicsSceneMouseRelease,
                         QEvent.GraphicsSceneMouseDoubleClick):
            pass
            #QGraphicsSceneMouseEvent *ev =
                #static_cast<QGraphicsSceneMouseEvent *>(event)
            #QGraphicsSceneMouseEvent e(ev->type())
            #e.setPos(QPointF(screenX, screenY))
            #e.setScenePos(QPointF(screenX + bounds.x(), screenY + bounds.y()))
            #e.setScreenPos(QPoint(screenX, screenY))
            #e.setButtonDownScreenPos(ev->button(), d->pressedPos)
            #e.setButtonDownScenePos
                #(ev->button(), QPointF(d->pressedPos.x() + bounds.x(),
                                      #d->pressedPos.y() + bounds.y()))
            #e.setButtons(ev->buttons())
            #e.setButton(ev->button())
            #e.setModifiers(ev->modifiers())
            #e.setAccepted(false)
            #QApplication::sendEvent(this, &e)

        elif eventType == QEvent.GraphicsSceneWheel:
            pass
            #QGraphicsSceneWheelEvent *ev =
                #static_cast<QGraphicsSceneWheelEvent *>(event)
            #QGraphicsSceneWheelEvent e(QEvent::GraphicsSceneWheel)
            #e.setPos(QPointF(screenX, screenY))
            #e.setScenePos(QPointF(screenX + bounds.x(), screenY + bounds.y()))
            #e.setScreenPos(QPoint(screenX, screenY))
            #e.setButtons(ev->buttons())
            #e.setModifiers(ev->modifiers())
            #e.setDelta(ev->delta())
            #e.setOrientation(ev->orientation())
            #e.setAccepted(false)
            #QApplication::sendEvent(this, &e)

        elif eventType in (QEvent.MouseButtonPress,
                           QEvent.MouseButtonRelease,
                           QEvent.MouseButtonDblClick,
                           QEvent.MouseMove):
            pass
            #QMouseEvent *ev = static_cast<QMouseEvent *>(event)
            #QEvent::Type type
            #if (ev->type() == QEvent::MouseButtonPress)
                #type = QEvent::GraphicsSceneMousePress
            #else if (ev->type() == QEvent::MouseButtonRelease)
                #type = QEvent::GraphicsSceneMouseRelease
            #else if (ev->type() == QEvent::MouseButtonDblClick)
                #type = QEvent::GraphicsSceneMouseDoubleClick
            #else
                #type = QEvent::GraphicsSceneMouseMove
            #QGraphicsSceneMouseEvent e(type)
            #e.setPos(QPointF(screenX, screenY))
            #e.setScenePos(QPointF(screenX + bounds.x(), screenY + bounds.y()))
            #e.setScreenPos(QPoint(screenX, screenY))
            #e.setButtonDownScreenPos(ev->button(), d->pressedPos)
            #e.setButtonDownScenePos
                #(ev->button(), QPointF(d->pressedPos.x() + bounds.x(),
                                      #d->pressedPos.y() + bounds.y()))
            #e.setButtons(ev->buttons())
            #e.setButton(ev->button())
            #e.setModifiers(ev->modifiers())
            #e.setAccepted(false)
            #QApplication::sendEvent(this, &e)

        elif eventType == QEvent.Wheel:
            pass
            #QWheelEvent *ev = static_cast<QWheelEvent *>(event)
            #QGraphicsSceneWheelEvent e(QEvent::GraphicsSceneWheel)
            #e.setPos(QPointF(screenX, screenY))
            #e.setScenePos(QPointF(screenX + bounds.x(), screenY + bounds.y()))
            #e.setScreenPos(QPoint(screenX, screenY))
            #e.setButtons(ev->buttons())
            #e.setModifiers(ev->modifiers())
            #e.setDelta(ev->delta())
            #e.setOrientation(ev->orientation())
            #e.setAccepted(false)
            #QApplication::sendEvent(this, &e)

        #else:
            # Send the event directly without any conversion.
            # Typically used for keyboard, focus, and enter/leave events.
            #QApplication.sendEvent(self, event)

        QApplication.sendEvent(self, event)
Ejemplo n.º 13
0
    def volume(self):
        linear_volume = QAudio.convertVolume(self.volume_slider.value() / 100,
                                             QAudio.LogarithmicVolumeScale,
                                             QAudio.LinearVolumeScale)

        return qRound(linear_volume * 100)
Ejemplo n.º 14
0
    def drawAICompassDisk(self, painter, area, halfspan):
        start = self.yaw - halfspan
        end = self.yaw + halfspan

        firstTick = math.ceil(
            start /
            self.COMPASS_DISK_RESOLUTION) * self.COMPASS_DISK_RESOLUTION
        lastTick = math.floor(
            end / self.COMPASS_DISK_RESOLUTION) * self.COMPASS_DISK_RESOLUTION

        radius = area.width() / 2
        innerRadius = radius * 0.96
        painter.resetTransform()
        painter.setBrush(self.instrumentBackground)
        painter.setPen(self.instrumentEdgePen)
        painter.drawEllipse(area)
        painter.setBrush(Qt.NoBrush)

        scalePen = QPen(Qt.black)
        scalePen.setWidthF(self.fineLineWidth)

        tickYaw = firstTick
        while tickYaw <= lastTick:
            displayTick = tickYaw
            if displayTick < 0:
                displayTick += 360
            elif displayTick >= 360:
                displayTick -= 360

            # yaw is in center.
            off = tickYaw - self.yaw
            # wrap that to ]-180..180]
            if off <= -180:
                off += 360
            elif off > 180:
                off -= 360

            painter.translate(area.center())
            painter.rotate(off)
            drewArrow = False
            isMajor = displayTick % self.COMPASS_DISK_MAJORTICK == 0

            if displayTick == 30 or displayTick == 60 or \
               displayTick ==120 or displayTick ==150 or \
               displayTick ==210 or displayTick ==240 or \
               displayTick ==300 or displayTick ==330:
                # draw a number
                painter.setPen(scalePen)
                self.drawTextCenter(painter,
                                    '{0}'.format(int(displayTick / 10)),
                                    self.smallTestSize, 0, -innerRadius * 0.75)
            else:
                if displayTick % self.COMPASS_DISK_ARROWTICK == 0:
                    if displayTick != 0:
                        markerPath = QPainterPath(
                            QPointF(
                                0, -innerRadius *
                                (1 - self.COMPASS_DISK_MARKERHEIGHT / 2)))
                        markerPath.lineTo(
                            innerRadius * self.COMPASS_DISK_MARKERWIDTH / 4,
                            -innerRadius)
                        markerPath.lineTo(
                            -innerRadius * self.COMPASS_DISK_MARKERWIDTH / 4,
                            -innerRadius)
                        markerPath.closeSubpath()
                        painter.setPen(scalePen)
                        painter.setBrush(Qt.SolidPattern)
                        painter.drawPath(markerPath)
                        painter.setBrush(Qt.NoBrush)
                        drewArrow = True
                    if displayTick % 90 == 0:
                        # Also draw a label
                        name = self.compassWindNames[qRound(displayTick / 45)]
                        painter.setPen(scalePen)
                        self.drawTextCenter(painter, name, self.mediumTextSize,
                                            0, -innerRadius * 0.75)

            # draw the scale lines. If an arrow was drawn, stay off from it.
            if drewArrow:
                p_start = QPoint(0, -innerRadius * 0.94)
            else:
                p_start = QPoint(0, -innerRadius)
            if isMajor:
                p_end = QPoint(0, -innerRadius * 0.86)
            else:
                p_end = QPoint(0, -innerRadius * 0.90)

            painter.setPen(scalePen)
            painter.drawLine(p_start, p_end)
            painter.resetTransform()
            tickYaw += self.COMPASS_DISK_RESOLUTION

        painter.setPen(scalePen)
        painter.translate(area.center())
        markerPath = QPainterPath(QPointF(0, -radius - 2))
        markerPath.lineTo(
            radius * self.COMPASS_DISK_MARKERWIDTH / 2,
            -radius - radius * self.COMPASS_DISK_MARKERHEIGHT - 2)
        markerPath.lineTo(
            -radius * self.COMPASS_DISK_MARKERWIDTH / 2,
            -radius - radius * self.COMPASS_DISK_MARKERHEIGHT - 2)
        markerPath.closeSubpath()
        painter.drawPath(markerPath)

        digitalCompassYCenter = -radius * 0.52
        digitalCompassHeight = radius * 0.28

        digitalCompassBottom = QPointF(
            0, digitalCompassYCenter + digitalCompassHeight)
        digitalCompassAbsoluteBottom = painter.transform().map(
            digitalCompassBottom)

        digitalCompassUpshift = 0
        if digitalCompassAbsoluteBottom.y() > self.height():
            digitalCompassUpshift = digitalCompassAbsoluteBottom.y(
            ) - self.height()

        digitalCompassRect = QRectF(-radius / 3,
                                    -radius * 0.52 - digitalCompassUpshift,
                                    radius * 2 / 3, radius * 0.28)
        painter.setPen(self.instrumentEdgePen)
        painter.drawRoundedRect(digitalCompassRect,
                                self.instrumentEdgePen.widthF() * 2 / 3,
                                self.instrumentEdgePen.widthF() * 2 / 3)

        # final safeguard for really stupid systems
        digitalCompassValue = qRound(self.yaw) % 360

        pen = QPen()
        pen.setWidthF(self.lineWidth)
        pen.setColor(Qt.white)
        painter.setPen(pen)

        self.drawTextCenter(painter, '%03d' % digitalCompassValue,
                            self.largeTextSize, 0,
                            -radius * 0.38 - digitalCompassUpshift)

        # The CDI
        if self.shouldDisplayNavigationData(
        ) and self.navigationTargetBearing != self.UNKNOWN_ATTITUDE and not math.isinf(
                self.navigationCrosstrackError):
            painter.resetTransform()
            painter.translate(area.center())
            # TODO : Sign might be wrong?
            # TODO : The case where error exceeds max. Truncate to max. and make that visible somehow.
            # bool errorBeyondRadius = false
            if abs(self.navigationCrosstrackError) > self.CROSSTRACK_MAX:
                #errorBeyondRadius = true
                if self.navigationCrosstrackError > 0:
                    self.navigationCrosstrackError = self.CROSSTRACK_MAX
                else:
                    self.navigationCrosstrackError = -self.CROSSTRACK_MAX

            r = radius * self.CROSSTRACK_RADIUS
            x = self.navigationCrosstrackError / self.CROSSTRACK_MAX * r
            y = math.sqrt(r * r -
                          x * x)  # the positive y, there is also a negative.

            sillyHeading = 0
            angle = sillyHeading - self.navigationTargetBearing  # TODO: sign.
            painter.rotate(-angle)

            pen = QPen()
            pen.setWidthF(self.lineWidth)
            pen.setColor(Qt.black)
            painter.setPen(pen)
            painter.drawLine(QPointF(x, y), QPointF(x, -y))
Ejemplo n.º 15
0
    def drawPitchScale(self, painter, area, intrusion, drawNumbersLeft,
                       drawNumbersRight):
        unused(intrusion)
        # The area should be quadratic but if not width is the major size.
        w = area.width()
        if w < area.height():
            w = area.height()

        pen = QPen()
        pen.setWidthF(self.lineWidth)
        pen.setColor(Qt.white)
        painter.setPen(pen)

        savedTransform = painter.transform()

        # find the mark nearest center
        snap = qRound(
            self.pitch /
            self.PITCH_SCALE_RESOLUTION) * self.PITCH_SCALE_RESOLUTION
        _min = snap - self.PITCH_SCALE_HALFRANGE
        _max = snap + self.PITCH_SCALE_HALFRANGE
        degrees = _min
        while degrees <= _max:
            isMajor = degrees % (self.PITCH_SCALE_RESOLUTION * 2) == 0
            linewidth = self.PITCH_SCALE_MINORWIDTH
            if isMajor:
                linewidth = self.PITCH_SCALE_MAJORWIDTH
            if abs(degrees) > self.PITCH_SCALE_WIDTHREDUCTION_FROM:
                # we want: 1 at PITCH_SCALE_WIDTHREDUCTION_FROM and PITCH_SCALE_WIDTHREDUCTION at 90.
                # That is PITCH_SCALE_WIDTHREDUCTION + (1-PITCH_SCALE_WIDTHREDUCTION) * f(pitch)
                # where f(90)=0 and f(PITCH_SCALE_WIDTHREDUCTION_FROM)=1
                # f(p) = (90-p) * 1/(90-PITCH_SCALE_WIDTHREDUCTION_FROM)
                # or PITCH_SCALE_WIDTHREDUCTION + f(pitch) - f(pitch) * PITCH_SCALE_WIDTHREDUCTION
                # or PITCH_SCALE_WIDTHREDUCTION (1-f(pitch)) + f(pitch)
                fromVertical = -90 - self.pitch
                if self.pitch >= 0:
                    fromVertical = 90 - self.pitch
                if fromVertical < 0:
                    fromVertical = -fromVertical
                temp = fromVertical * 1 / (
                    90.0 - self.PITCH_SCALE_WIDTHREDUCTION_FROM)
                linewidth *= (self.PITCH_SCALE_WIDTHREDUCTION * (1 - temp) +
                              temp)
            shift = self.pitchAngleToTranslation(w, self.pitch - degrees)

            # TODO: Intrusion detection and evasion. That is, don't draw
            # where the compass has intruded.
            painter.translate(0, shift)
            start = QPointF(-linewidth * w, 0)
            end = QPointF(linewidth * w, 0)
            painter.drawLine(start, end)

            if isMajor and (drawNumbersLeft or drawNumbersRight):
                displayDegrees = degrees
                if displayDegrees > 90:
                    displayDegrees = 180 - displayDegrees
                elif displayDegrees < -90:
                    displayDegrees = -180 - displayDegrees
                if self.SHOW_ZERO_ON_SCALES or degrees:
                    if drawNumbersLeft:
                        self.drawTextRightCenter(
                            painter, '{0}'.format(displayDegrees),
                            self.mediumTextSize,
                            -self.PITCH_SCALE_MAJORWIDTH * w - 10, 0)
                    if drawNumbersRight:
                        self.drawTextLeftCenter(
                            painter, '{0}'.format(displayDegrees),
                            self.mediumTextSize,
                            self.PITCH_SCALE_MAJORWIDTH * w + 10, 0)

            painter.setTransform(savedTransform)
            degrees += self.PITCH_SCALE_RESOLUTION