Example #1
0
 def toQPainterPath(self):
     """Return a QPainterPath containing all segments of this path.
     """
     if not self.isValid():
         raise Path2dException('invalid path')
     p = QPainterPath()
     sx, sy = self._elements[0]
     if len(self._elements[1]) == 2:
         # Only add a start point if the QPainterPath will start with a
         # line, not an arc.
         p.moveTo(sx, sy)
     for e in self._elements[1:]:
         if len(e) == 2:
             p.lineTo(*e)
             sx, sy = e
         else:
             (ex, ey), (cx, cy), arcDir = e
             r = hypot(ex-cx, ey-cy)
             d = r*2
             sa = degrees(atan2(sy-cy, sx-cx)) % 360.0
             ea = degrees(atan2(ey-cy, ex-cx)) % 360.0
             # NOTE: machtool uses a right-handed cartesian coordinate
             #       system with the Y+ up. Because of this, the QRectF
             #       used to define the arc has a negative height. This
             #       makes a positive arc angle sweep cclw as it should.
             rect = QRectF(cx - r, cy + r, d, -d)
             if arcDir == 'cclw':
                 span = (ea + 360.0 if ea < sa else ea) - sa
             else:
                 span = -((sa + 360.0 if sa < ea else sa) - ea)
             p.arcMoveTo(rect, sa)
             p.arcTo(rect, sa, span)
             sx, sy = ex, ey
     return p
Example #2
0
    def itemRegion(self, index):

        if not index.isValid() or not self.model():
            return QRegion()
        return QRegion()

        # TODO: what to do with this code?

        if index.column != 1:
            return self.itemRect(index)

        if self.model().data(index).toDouble()[0] <= 0.0:
            return QRegion()

        startAngle = 0.0
        for row in xrange(self.model().rowCount(self.rootIndex())):
            sliceIndex = self.model().index(row, 1, self.rootIndex())
            value = self.model().data(sliceIndex).toDouble()[0]

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

                if sliceIndex == index:
                    slicePath = QPainterPath()
                    slicePath.moveTo(self.totalSize/2, self.totalSize/2)
                    slicePath.arcTo(self.margin, self.margin,
                                    self.margin+self.histogramSize,
                                    self.margin+self.histogramSize,
                                    startAngle, angle)
                    slicePath.closeSubpath()
                    return QRegion(slicePath.toFillPolygon().toPolygon())

                startAngle += angle

        return QRegion()
Example #3
0
 def toQPainterPath(self):
     """Return a QPainterPath containing all segments of this path.
     """
     if not self.isValid():
         raise Path2dException('invalid path')
     p = QPainterPath()
     sx, sy = self._elements[0]
     if len(self._elements[1]) == 2:
         # Only add a start point if the QPainterPath will start with a
         # line, not an arc.
         p.moveTo(sx, sy)
     for e in self._elements[1:]:
         if len(e) == 2:
             p.lineTo(*e)
             sx, sy = e
         else:
             (ex, ey), (cx, cy), arcDir = e
             r = hypot(ex - cx, ey - cy)
             d = r * 2
             sa = degrees(atan2(sy - cy, sx - cx)) % 360.0
             ea = degrees(atan2(ey - cy, ex - cx)) % 360.0
             # NOTE: machtool uses a right-handed cartesian coordinate
             #       system with the Y+ up. Because of this, the QRectF
             #       used to define the arc has a negative height. This
             #       makes a positive arc angle sweep cclw as it should.
             rect = QRectF(cx - r, cy + r, d, -d)
             if arcDir == 'cclw':
                 span = (ea + 360.0 if ea < sa else ea) - sa
             else:
                 span = -((sa + 360.0 if sa < ea else sa) - ea)
             p.arcMoveTo(rect, sa)
             p.arcTo(rect, sa, span)
             sx, sy = ex, ey
     return p
Example #4
0
class RobotView(QGraphicsItem):
    def __init__(self, robot):
        super(RobotView, self).__init__()
        self.robot = robot
        self.outline = QPainterPath()
        self.cut_angle = 0.0
        self.setFlags(QGraphicsItem.ItemIsSelectable)

    @property
    def uuid(self):
        return self.robot.uuid

    @property
    def color(self):
        if self.isSelected():
            return GREEN
        elif self.robot.is_blue:
            return BLUE
        elif self.robot.is_yellow:
            return YELLOW
        else:
            return BLACK

    def position(self):
        x, y, width, height = s(self.robot.x, self.robot.y, self.robot.world.length, self.robot.world.width)
        radius = s(self.robot.radius)

        self.cut_angle = acos(self.robot.front_cut / self.robot.radius)

        self.outline = QPainterPath()
        self.outline.moveTo(radius, 0)
        self.outline.arcTo(-radius, -radius, 2 * radius, 2 * radius, 0, 360 - 2 * self.cut_angle)
        self.outline.closeSubpath()

        self.setPos(x, -y)

    def boundingRect(self):
        radius = s(self.robot.radius)
        return QRectF(-radius, -radius, 2 * radius, 2 * radius)

    def paint(self, painter, option, widget=None):
        # Save transformation:
        painter.save()

        color = self.color

        # Change position
        painter.setBrush(color)
        painter.setPen(color)

        robot_rotation = self.robot.angle or 0.0
        # Draw robot shape
        painter.rotate(-self.cut_angle - robot_rotation)
        painter.drawPath(self.outline)
        painter.rotate(self.cut_angle + robot_rotation)

        # Reset transformation
        painter.restore()
Example #5
0
def draw_arc(x, y, radius_in, radius_out, angle_init, angle_end, painter):
    path = QPainterPath()

    path.moveTo(x + radius_in * cos(angle_init), y + radius_in * sin(angle_init))
    path.arcTo(x - radius_out, y - radius_out, 2 * radius_out, 2 * radius_out, angle_init, angle_end - angle_init)
    path.arcTo(x - radius_in, y - radius_in, 2 * radius_in, 2 * radius_in, angle_end, angle_init - angle_end)
    path.closeSubpath()

    painter.drawPath(path)
Example #6
0
File: Track.py Project: Pesa/forse
 def __init__(self, parent, pos, angle, length, color, radius, pit=False):
     PhysicalSector.__init__(self, parent, pos, angle, length, color, pit)
     self.angle = 180.0 * self.length() / (math.pi * radius)
     startAngle = 180.0 if radius > 0 else 0
     offset = _pitDistance if pit else 0
     radius -= offset
     rect = QRectF(offset + (2 * radius if radius < 0 else 0), -abs(radius),
                   2 * abs(radius), 2 * abs(radius))
     path = QPainterPath(QPointF(offset, 0))
     path.arcTo(rect, startAngle, self.angle)
     self.setPath(path)
Example #7
0
 def drawValue(self, p, baseRect, value, delta):
     if value == self.m_min:
         return
     dataPath = QPainterPath()
     dataPath.setFillRule(Qt.WindingFill)
     if value == self.m_max:
         dataPath.addEllipse(baseRect)
     else:
         arcLength = 360 / delta
         dataPath.moveTo(baseRect.center())
         dataPath.arcTo(baseRect, self.m_nullPosition, -arcLength)
         dataPath.lineTo(baseRect.center())
     p.setBrush(self.palette().highlight())
     p.setPen(QPen(self.palette().shadow().color(), self.m_dataPenWidth))
     p.drawPath(dataPath)
Example #8
0
    def setupGraphics(self):
        """
        Set up the graphics.
        """
        shape_rect = QRectF(-24, -24, 48, 48)

        self.shapeItem = NodeBodyItem(self)
        self.shapeItem.setShapeRect(shape_rect)
        self.shapeItem.setAnimationEnabled(self.__animationEnabled)

        # Rect for widget's 'ears'.
        anchor_rect = QRectF(-31, -31, 62, 62)
        self.inputAnchorItem = SinkAnchorItem(self)
        input_path = QPainterPath()
        start_angle = 180 - self.ANCHOR_SPAN_ANGLE / 2
        input_path.arcMoveTo(anchor_rect, start_angle)
        input_path.arcTo(anchor_rect, start_angle, self.ANCHOR_SPAN_ANGLE)
        self.inputAnchorItem.setAnchorPath(input_path)

        self.outputAnchorItem = SourceAnchorItem(self)
        output_path = QPainterPath()
        start_angle = self.ANCHOR_SPAN_ANGLE / 2
        output_path.arcMoveTo(anchor_rect, start_angle)
        output_path.arcTo(anchor_rect, start_angle, -self.ANCHOR_SPAN_ANGLE)
        self.outputAnchorItem.setAnchorPath(output_path)

        self.inputAnchorItem.hide()
        self.outputAnchorItem.hide()

        # Title caption item
        self.captionTextItem = NameTextItem(self)

        self.captionTextItem.setPlainText("")
        self.captionTextItem.setPos(0, 33)

        def iconItem(standard_pixmap):
            item = GraphicsIconItem(self,
                                    icon=standard_icon(standard_pixmap),
                                    iconSize=QSize(16, 16))
            item.hide()
            return item

        self.errorItem = iconItem(QStyle.SP_MessageBoxCritical)
        self.warningItem = iconItem(QStyle.SP_MessageBoxWarning)
        self.infoItem = iconItem(QStyle.SP_MessageBoxInformation)

        self.prepareGeometryChange()
        self.__boundingRect = None
Example #9
0
    def setupGraphics(self):
        """
        Set up the graphics.
        """
        shape_rect = QRectF(-24, -24, 48, 48)

        self.shapeItem = NodeBodyItem(self)
        self.shapeItem.setShapeRect(shape_rect)
        self.shapeItem.setAnimationEnabled(self.__animationEnabled)

        # Rect for widget's 'ears'.
        anchor_rect = QRectF(-31, -31, 62, 62)
        self.inputAnchorItem = SinkAnchorItem(self)
        input_path = QPainterPath()
        start_angle = 180 - self.ANCHOR_SPAN_ANGLE / 2
        input_path.arcMoveTo(anchor_rect, start_angle)
        input_path.arcTo(anchor_rect, start_angle, self.ANCHOR_SPAN_ANGLE)
        self.inputAnchorItem.setAnchorPath(input_path)

        self.outputAnchorItem = SourceAnchorItem(self)
        output_path = QPainterPath()
        start_angle = self.ANCHOR_SPAN_ANGLE / 2
        output_path.arcMoveTo(anchor_rect, start_angle)
        output_path.arcTo(anchor_rect, start_angle, - self.ANCHOR_SPAN_ANGLE)
        self.outputAnchorItem.setAnchorPath(output_path)

        self.inputAnchorItem.hide()
        self.outputAnchorItem.hide()

        # Title caption item
        self.captionTextItem = NameTextItem(self)

        self.captionTextItem.setPlainText("")
        self.captionTextItem.setPos(0, 33)

        def iconItem(standard_pixmap):
            item = GraphicsIconItem(self, icon=standard_icon(standard_pixmap),
                                    iconSize=QSize(16, 16))
            item.hide()
            return item

        self.errorItem = iconItem(QStyle.SP_MessageBoxCritical)
        self.warningItem = iconItem(QStyle.SP_MessageBoxWarning)
        self.infoItem = iconItem(QStyle.SP_MessageBoxInformation)

        self.prepareGeometryChange()
        self.__boundingRect = None
Example #10
0
    def __init__(self, radiusOut, raiusIn, angle, arcLen, parent=None):
        QGraphicsPathItem.__init__(self, parent=parent)
        self._radiusOut = radiusOut
        self._raiusIn = raiusIn
        self._angle = angle
        self._arcLen = arcLen

        self._pen = QPen(QColor('#000000'))
        self._pen.setWidth(1)
        self.setPen(self._pen)

        self._hoverPen = QPen(QColor('#000000'))
        self._hoverPen.setWidth(2)

        brush = QBrush(QColor('#FF9966'))
        self.setBrush(brush)

        rectOut = QRectF(-radiusOut, -radiusOut, radiusOut*2.0, radiusOut*2.0)
        rectIn = QRectF(-raiusIn, -raiusIn, raiusIn*2.0, raiusIn*2.0)

        startAngle = angle - arcLen/2.0
        endAngle = angle + arcLen/2.0

        path = QPainterPath()
        path.arcMoveTo(rectIn, startAngle)
        path.arcTo(rectOut, startAngle, arcLen)
        path.arcTo(rectIn, endAngle, 0)
        path.arcTo(rectIn, endAngle, -arcLen)

        self.setPath(path)

        self._isHover = False

        self._ioDragFirstPos = None
Example #11
0
 def paintEvent(self, e):
     self._plotter.begin(self)
     if self._reaction.GetCatalyst().GetUsed():
         change = self._reaction.GetCatalyst().GetEfficacy()
     else:
         change = 1
     eqmpoint = 150 / change
     if change > 1:
         eqmpoint -= 0.1 * self._reaction.GetCatalyst().GetInitialMoles()
     elif change < 1:
         eqmpoint += 0.1 * self._reaction.GetCatalyst().GetInitialMoles()
     pen = QPen(Qt.black, 2, Qt.SolidLine)
     self._plotter.setPen(pen)
     self._plotter.drawLine(80, 20, 80, 220)
     self._plotter.drawLine(80, 220, 400, 220)
     self._plotter.setPen(QPen(self._reaction.GetReactantColour()))
     reactionpath = QPainterPath()
     reactionpath.moveTo(QPointF(80, 20))
     reactionpath.arcTo(80, -80 + self._plotter.GetFinalY(), eqmpoint * 2,
                        200 - (2 * self._plotter.GetFinalY()), 180, 90)
     reactionpath.lineTo(400, 120 - self._plotter.GetFinalY())
     self._plotter.drawPath(reactionpath)
     self._plotter.setPen(QPen(self._reaction.GetProductColour()))
     productpath = QPainterPath()
     productpath.moveTo(QPointF(80, 220))
     productpath.arcTo(80, 120 + self._plotter.GetFinalY(), eqmpoint * 2,
                       200 - (2 * self._plotter.GetFinalY()), 180, -90)
     productpath.lineTo(400, 120 + self._plotter.GetFinalY())
     self._plotter.drawPath(productpath)
     if not self._forprinting:
         white = QColor(240, 240, 240)
         self._plotter.setPen(QPen(white))
         self._plotter.setBrush(white)
         self._plotter.drawRect(82 + self.parent().GetAnimUpdates() * 0.23,
                                20, 320, 198)
     self._plotter.setPen(QColor(0, 0, 0))
     self._plotter.drawText(180, 235, "Time")
     self._plotter.drawText(0, 120, self._graphof)
     self._plotter.end()
Example #12
0
 def drawGraph(self, plotter, change):
     pen = QPen(Qt.black, 2, Qt.SolidLine)
     plotter.setPen(pen)
     plotter.drawLine(20, 20, 20, 220)
     plotter.drawLine(20, 220, 220, 220)
     reactants = self._reaction.GetReactants()
     AverageReactantConc = 0
     for x in range(self._reaction.REACTING_SPECIES_LIMIT):
         AverageReactantConc += reactants[x].GetInitialMoles()
     AverageReactantConc /= (len(reactants) * self._reaction.GetVolume())
     plotter.setPen(QPen(plotter.GetReactantColour(), 2, Qt.SolidLine))
     reactionpath = QPainterPath()
     reactionpath.moveTo(QPointF(20, 20))
     reactionpath.arcTo(20, -70, 300 * change, 180, 180, 90)
     reactionpath.lineTo(220, 110)
     plotter.drawPath(reactionpath)
     plotter.setPen(QPen(plotter.GetProductColour(), 2, Qt.SolidLine))
     productpath = QPainterPath()
     productpath.moveTo(QPointF(20, 220))
     productpath.arcTo(20, 130, 300 * change, 180, 180, -90)
     productpath.lineTo(220, 130)
     plotter.drawPath(productpath)
Example #13
0
 def drawGraph(self, plotter, change):
     pen = QPen(Qt.black, 2, Qt.SolidLine)
     plotter.setPen(pen)
     plotter.drawLine(20, 20, 20, 220)
     plotter.drawLine(20, 220, 220, 220)
     reactants = self._reaction.GetReactants()
     AverageReactantConc = 0
     for x in range(self._reaction.REACTING_SPECIES_LIMIT):
         AverageReactantConc += reactants[x].GetInitialMoles()
     AverageReactantConc /= (len(reactants) * self._reaction.GetVolume())
     plotter.setPen(QPen(plotter.GetReactantColour(), 2, Qt.SolidLine))
     reactionpath = QPainterPath()
     reactionpath.moveTo(QPointF(20, 20))
     reactionpath.arcTo(20, -70, 300 * change, 180, 180, 90)
     reactionpath.lineTo(220, 110)
     plotter.drawPath(reactionpath)
     plotter.setPen(QPen(plotter.GetProductColour(), 2, Qt.SolidLine))
     productpath = QPainterPath()
     productpath.moveTo(QPointF(20, 220))
     productpath.arcTo(20, 130, 300 * change, 180, 180, -90)
     productpath.lineTo(220, 130)
     plotter.drawPath(productpath)
Example #14
0
 def paintEvent(self, e):
     self._plotter.begin(self)
     if self._reaction.GetCatalyst().GetUsed():
         change = self._reaction.GetCatalyst().GetEfficacy()
     else:
         change = 1
     eqmpoint = 150/change
     if change > 1:
         eqmpoint -= 0.1 * self._reaction.GetCatalyst().GetInitialMoles()
     elif change < 1:
         eqmpoint += 0.1 * self._reaction.GetCatalyst().GetInitialMoles()
     pen = QPen(Qt.black, 2, Qt.SolidLine)
     self._plotter.setPen(pen)
     self._plotter.drawLine(80, 20, 80, 220)
     self._plotter.drawLine(80, 220, 400, 220)
     self._plotter.setPen(QPen(self._reaction.GetReactantColour()))
     reactionpath = QPainterPath()
     reactionpath.moveTo(QPointF(80, 20))
     reactionpath.arcTo(80, -80 + self._plotter.GetFinalY(), eqmpoint * 2, 200 - (2 * self._plotter.GetFinalY()), 180, 90)
     reactionpath.lineTo(400, 120 - self._plotter.GetFinalY())
     self._plotter.drawPath(reactionpath)
     self._plotter.setPen(QPen(self._reaction.GetProductColour()))
     productpath = QPainterPath()
     productpath.moveTo(QPointF(80, 220))
     productpath.arcTo(80, 120 + self._plotter.GetFinalY(), eqmpoint * 2, 200 - (2 * self._plotter.GetFinalY()), 180, -90)
     productpath.lineTo(400, 120 + self._plotter.GetFinalY())
     self._plotter.drawPath(productpath)
     if not self._forprinting:
         white = QColor(240, 240, 240)
         self._plotter.setPen(QPen(white))
         self._plotter.setBrush(white)
         self._plotter.drawRect(82 + self.parent().GetAnimUpdates() * 0.23, 20, 320, 198)
     self._plotter.setPen(QColor(0, 0, 0))
     self._plotter.drawText(180, 235, "Time")
     self._plotter.drawText(0, 120, self._graphof)
     self._plotter.end()
Example #15
0
def _generate_popup_path(rect, xRadius, yRadius, arrowSize, anchor):
    """ Generate the QPainterPath used to draw the outline of the popup.

    Parameters
    ----------
    rect : QRect
        Bounding rect for the popup.

    xRadius, yRadius : int
        x and y radius of the popup.

    arrowSize : QSize
        Width and height of the popup anchor arrow.

    anchor : int
        Positioning of the popup relative to the parent. Determines the
        position of the arrow.

    Returns
    -------
    result : QPainterPath
        Path that can be passed to QPainter.drawPath to render popup.

    """
    awidth, aheight = arrowSize.width(), arrowSize.height()
    draw_arrow = (awidth > 0 and aheight > 0)

    if anchor == QBubbleView.AnchorRight:
        rect.adjust(aheight, 0, 0, 0)
    elif anchor == QBubbleView.AnchorLeft:
        rect.adjust(0, 0, -aheight, 0)
    elif anchor == QBubbleView.AnchorBottom:
        rect.adjust(0, aheight, 0, 0)
    else:
        rect.adjust(0, 0, 0, -aheight)

    r = rect.normalized()

    if r.isNull():
        return

    hw = r.width() / 2
    hh = r.height() / 2

    xRadius = 100 * min(xRadius, hw) / hw
    yRadius = 100 * min(yRadius, hh) / hh

    # The starting point of the path is the top left corner
    x = r.x()
    y = r.y()
    w = r.width()
    h = r.height()
    rxx2 = w * xRadius / 100
    ryy2 = h * yRadius / 100

    center = r.center()

    path = QPainterPath()
    path.arcMoveTo(x, y, rxx2, ryy2, 180)
    path.arcTo(x, y, rxx2, ryy2, 180, -90)

    if anchor == QBubbleView.AnchorBottom and draw_arrow:
        path.lineTo(center.x() - awidth, y)
        path.lineTo(center.x(), y - aheight)
        path.lineTo(center.x() + awidth, y)

    path.arcTo(x + w - rxx2, y, rxx2, ryy2, 90, -90)

    if anchor == QBubbleView.AnchorLeft and draw_arrow:
        path.lineTo(x + w, center.y() - awidth)
        path.lineTo(x + w + aheight, center.y())
        path.lineTo(x + w, center.y() + awidth)

    path.arcTo(x + w - rxx2, y + h - ryy2, rxx2, ryy2, 0, -90)

    if anchor == QBubbleView.AnchorTop and draw_arrow:
        path.lineTo(center.x() + awidth, y + h)
        path.lineTo(center.x(), y + h + aheight)
        path.lineTo(center.x() - awidth, y + h)

    path.arcTo(x, y + h - ryy2, rxx2, ryy2, 270, -90)

    if anchor == QBubbleView.AnchorRight and draw_arrow:
        path.lineTo(x, center.y() + awidth)
        path.lineTo(x - aheight, center.y())
        path.lineTo(x,  center.y() - awidth)

    path.closeSubpath()
    return path
class DMCircularGauge(QWidget):
    sci_notation = False
    _value = 0.0
    percentage = 0.0

    lolo_arc = QPainterPath()
    low_arc = QPainterPath()
    high_arc = QPainterPath()
    hihi_arc = QPainterPath()

    def __init__(self, channel=None, range_low=None, range_high=None, parent=None):
        super(DMCircularGauge, self).__init__(parent)

        self.channel = channel
        self._channel = self.channel.value
        if range_low is None:
            range_low = self.channel.range()[0]
        if range_high is None:
            range_high = self.channel.range()[1]
        if range_low > range_high:
            temp = range_low
            range_low = range_high
            range_high = temp
        self.range = [range_low, range_high]
        self.connect(self.channel, SIGNAL('new_value(float)'), self.update_value)
        self.connect(self.channel, SIGNAL('new_limits(float, float, float, float)'), self.update_limits)

        self.width_ref = 400.0
        self.height_ref = 240.0
        self.resize(self.width_ref, self.height_ref)
        self.ref_aspect_ratio = self.width_ref / self.height_ref

        self.dial_v_offset = self.height() * 0.1
        self.dial_height = self.width() / 2.0
        self.dial_width = self.width()

        self.dial = QPainterPath(QPointF(0.0, self.dial_height))
        self.dial.arcTo(0.0, 1.0, self.dial_width, self.dial_height * 2, 180, -180)
        self.dial.lineTo(self.dial_width, self.height_ref)
        self.dial.lineTo(0.0, self.height_ref)
        self.dial.lineTo(0.0, self.dial_height)

        # self.dial_bg = QRadialGradient(QPointF(self.width()/2.0, self.height()-self.dial_v_offset), self.dial_height)
        # self.dial_bg.setColorAt(0, Qt.lightGray)
        # self.dial_bg.setColorAt(0.98, QColor(50, 50, 50, 255))
        # self.dial_bg.setColorAt(1, Qt.black)

        needle_base_width = 18
        self.needle = QPolygonF([QPoint(0, -needle_base_width/2.0),
                                 QPoint(self.dial_height * 0.9, 0.0),
                                 QPoint(0, needle_base_width / 2.0)])
        self.needle_color = Qt.gray

        # self.needle_left = QPolygonF([QPoint(0, 0),
        #                               QPoint(0, -needle_base_width/2.0),
        #                               QPoint(self.dial_height*0.9, 0.0)])
        # self.needle_right = QPolygonF([QPoint(0, 0),
        #                               QPoint(0, needle_base_width / 2.0),
        #                               QPoint(self.dial_height * 0.9, 0.0)])

        pin_diameter = 22
        self.pin_rect = QRectF(-pin_diameter / 2.0, -pin_diameter / 2.0, pin_diameter, pin_diameter)
        # self.pin_bg = QRadialGradient(QPointF(0.0, -pin_diameter / 5.0), pin_diameter * 0.75)
        # self.pin_bg.setColorAt(0, Qt.lightGray)
        # self.pin_bg.setColorAt(1, Qt.black)

        # self.shadow_rect = QRectF(-self.dial_width / 2, -self.dial_height / 2,
        #                           self.dial_width, self.dial_height * 1.1)
        # self.gloss_rect = QRectF(-self.dial_width / 5, -self.dial_height / 2,
        #                          self.dial_width / 2.5, self.dial_height / 2)
        # self.gloss_gradient = QLinearGradient(QPointF(0.0, -self.dial_height / 2), QPointF(0.0, 0.0))
        # self.gloss_gradient.setColorAt(0.0, QColor(255, 255, 255, 120))
        # self.gloss_gradient.setColorAt(0.95, QColor(255, 255, 255, 0))

        limits = self.channel.limits()
        self.update_limits(limits[0], limits[1], limits[2], limits[3])

        self.pv_label_font = QFont()
        self.pv_label_font.setPixelSize(22)
        self.pv_label_font.setWeight(QFont.Bold)
        # font_metric = QFontMetrics(self.pv_label_font)
        # pv_label = self.channel.egu  # self.channel.name + ' (' + self.channel.egu + ')'
        # text_path = QPainterPath()
        # text_path.addText(QPointF(0.0 - font_metric.width(pv_label) / 2.0,
        #                           (self.dial_height / 2.0) + (font_metric.height() * 1.5)),
        #                   self.pv_label_font,
        #                   pv_label)
        # stroke_path = QPainterPathStroker()
        # stroke_path.setWidth(1)
        # self.pv_label_path = QPainterPath(stroke_path.createStroke(text_path) + text_path).simplified()

    def paintEvent(self, event):
        # Initialize QPainter properties
        painter = QPainter()
        painter.begin(self)
        painter.setRenderHint(QPainter.Antialiasing)
        if self.height() <= self.width() / self.ref_aspect_ratio:
            v_scale = self.height()
            h_scale = v_scale * self.ref_aspect_ratio
        else:
            h_scale = self.width()
            v_scale = h_scale / self.ref_aspect_ratio
        # Scale all objects proportionate to window size
        painter.scale(h_scale / self.width_ref, v_scale / self.height_ref)
        painter.setClipPath(self.dial)  # Don't allow objects or text to extend outside of main dial shape
        painter.save()

        # First draw main gauge background
        pen = QPen(painter.pen())
        pen.setWidth(1)
        pen.setColor(Qt.black)
        painter.setPen(pen)
        painter.setBrush(QColor(100, 100, 100, 255))  # self.dial_bg)
        painter.drawPath(self.dial)

        # Add Minor and Major Alarm limit bars
        pen.setWidth(16)
        pen.setCapStyle(Qt.FlatCap)
        pen.setJoinStyle(Qt.BevelJoin)

        pen.setColor(Qt.yellow)
        painter.setPen(pen)
        painter.setBrush(Qt.NoBrush)
        painter.drawPath(self.low_arc)
        painter.drawPath(self.high_arc)

        pen.setColor(Qt.red)
        painter.setPen(pen)
        painter.drawPath(self.lolo_arc)
        painter.drawPath(self.hihi_arc)

        painter.restore()

        # Display PV current value
        painter.save()
        font = QFont()
        font.setPixelSize(45)
        painter.setFont(font)
        sevr = self.channel.sevr.lower()
        if sevr == 'major':
            color = Qt.red
        elif sevr == 'minor':
            color = Qt.yellow
        elif sevr == 'invalid':
            color = Qt.magenta
        else:
            color = Qt.green
        pen.setColor(color)
        painter.setPen(pen)
        font_metric = QFontMetrics(font)
        painter.translate(self.dial_width / 2, self.dial_height / 2)
        label = self.format_label(self.channel_value)
        painter.drawText(QPointF(0.0 - font_metric.width(label) / 2.0, font_metric.height() / 2.0),
                         label)

        # Display PV name
        painter.setFont(self.pv_label_font)
        pen.setColor(Qt.black)  # Qt.darkCyan)
        pen.setWidth(1)
        painter.setPen(pen)
        # brush = QBrush(Qt.darkCyan)
        # painter.setBrush(brush)
        font_metric = QFontMetrics(self.pv_label_font)
        pv_label = self.channel.egu  # self.channel.name + ' (' + self.channel.egu + ')'
        painter.drawText(QPointF(0.0 - font_metric.width(pv_label) / 2.0,
                                 (self.dial_height / 2.0) + (font_metric.height() * 1.5)),
                         pv_label)
        # painter.drawPath(self.pv_label_path)
        painter.restore()

        # Next add division markers
        painter.save()
        painter.translate(self.dial_width / 2, self.dial_height * 0.98)
        pen.setColor(Qt.black)  # Qt.cyan)
        pen.setWidth(2)
        painter.setPen(pen)
        for i in range(0, 31):
            if (i % 5) != 0:
                painter.drawLine(-self.dial_width / 2.1, 0.0, -self.dial_width / 2.2, 0.0)
            else:
                painter.drawLine(-self.dial_width / 2.1, 0.0, -self.dial_width / 2.3, 0.0)
            painter.rotate(6.0)
        painter.restore()

        # Layout division text labels
        painter.save()
        painter.translate(self.dial_width / 2, self.dial_height * 0.98)
        pen.setColor(Qt.black)  # Qt.cyan)
        painter.setPen(pen)
        font = QFont()
        font.setPixelSize(18)
        painter.setFont(font)
        font_metric = QFontMetrics(font)
        labels = linspace(self.lim_low, self.lim_hi, 7)
        painter.rotate(-90)
        for i in range(0, 7):
            label = self.format_label(labels[i])
            painter.drawText(QPointF(0.0 - font_metric.width(label) / 2.0, -self.dial_height * 0.75), label)
            painter.rotate(30)
        painter.restore()

        # Draw needle at appropriate angle for data
        painter.save()
        painter.translate(self.dial_width / 2, self.dial_height * 0.98)
        painter.rotate(-180 * (1.0 - self.percentage))

        pen.setColor(QColor(self.needle_color).darker(200))
        pen.setWidth(1)
        painter.setPen(pen)
        painter.setBrush(self.needle_color)
        painter.drawPolygon(self.needle)
        painter.restore()

        # if self.percentage <= 0.5:
        #     shadow = max(490 * self.percentage, 127)
        #     needle_left_color = QColor(0, shadow, shadow)  # Qt.darkCyan  # QColor(80,80,80,255)
        #     needle_right_color = Qt.cyan  # QColor(230,230,230,255)
        # else:
        #     shadow = max(125 / self.percentage, 127)
        #     needle_left_color = Qt.cyan  # QColor(230,230,230,255)
        #     needle_right_color = QColor(0, shadow, shadow)  # Qt.darkCyan  # QColor(80,80,80,255)
        #
        # # Draw Highlight side of needle
        # pen.setWidth(1)
        # pen.setColor(Qt.gray)  # needle_left_color)
        # painter.setPen(pen)
        # painter.setBrush(Qt.gray)  # needle_left_color)
        # painter.drawPolygon(self.needle_left)
        #
        # # Draw shadow side of needle
        # pen.setColor(Qt.gray)  # needle_right_color)
        # painter.setPen(pen)
        # painter.setBrush(Qt.gray)  # needle_right_color)
        # painter.drawPolygon(self.needle_right)
        # painter.restore()

        # Draw needle axel pin
        painter.save()
        pen.setWidth(1)
        pen.setColor(Qt.black)
        painter.setPen(pen)
        painter.setBrush(QColor(50, 50, 50, 255))  # self.pin_bg)
        painter.translate(self.dial_width / 2, self.dial_height * 0.98)
        painter.drawEllipse(self.pin_rect)
        painter.restore()

        # Draw glass reflection and shadow effects
        # painter.save()
        # painter.translate(self.dial_width / 2.0, self.dial_height / 2.0)
        # painter.setPen(Qt.NoPen)
        # painter.setBrush(QColor(0, 0, 0, 20))
        # painter.drawEllipse(self.shadow_rect)
        # painter.setBrush(self.gloss_gradient)
        # painter.drawEllipse(self.gloss_rect)
        # painter.restore()

        painter.end()

    def format_label(self, label):
        # Automatically switch to scientific notation for very large or very small numbers
        if self.sci_notation or abs(label) >= 10000 or abs(label) < 0.01:
            return QString().setNum(label, 'g', 2)
        else:
            return QString().setNum(label, 'f', 2)

    @property
    def lim_hi(self):
        return self.range[1]

    @lim_hi.setter
    def lim_hi(self, lim):
        self.range[1] = lim

    @property
    def lim_low(self):
        return self.range[0]

    @lim_low.setter
    def lim_low(self, lim):
        self.range[0] = lim

    def update_value(self, value=0.0):
        self.channel_value = value
        self.update()

    @property
    def channel_value(self):
        return self._value

    @channel_value.setter
    def channel_value(self, value):
        self._value = value
        self.update_percentage()

    def update_limits(self, lolo, low, high, hihi):
        full_range = self.lim_hi - self.lim_low
        left_x = self.dial_width * 0.025
        right_x = self.dial_width * 0.975

        angle = -180 * (1 - (self.lim_hi - lolo) / full_range)
        self.lolo_arc = self.make_arc(left_x, self.dial_height, 180.0, angle)

        angle = -180 * (1 - (self.lim_hi - low) / full_range)
        self.low_arc = self.make_arc(left_x, self.dial_height, 180.0, angle)

        angle = 180 * (self.lim_hi - high) / full_range
        self.high_arc = self.make_arc(right_x, self.dial_height, 0.0, angle)

        angle = 180 * (self.lim_hi - hihi) / full_range
        self.hihi_arc = self.make_arc(right_x, self.dial_height, 0.0, angle)

    def make_arc(self, start_x, start_y, start_angle, end_angle):
        arc = QPainterPath(QPointF(start_x, start_y))
        arc.arcTo(self.dial_width * 0.025, self.dial_width * 0.025,  # self.dial_width * 0.15,
                  self.dial_width * 0.95, self.dial_width * 0.95,
                  start_angle, end_angle)
        return arc

    def update_percentage(self):
        value = min(max(self.channel_value, self.lim_low), self.lim_hi)
        self.percentage = (value - self.lim_low) / (self.lim_hi - self.lim_low)

    def channels(self):
        pass
 def make_arc(self, start_x, start_y, start_angle, end_angle):
     arc = QPainterPath(QPointF(start_x, start_y))
     arc.arcTo(self.dial_width * 0.025, self.dial_width * 0.025,  # self.dial_width * 0.15,
               self.dial_width * 0.95, self.dial_width * 0.95,
               start_angle, end_angle)
     return arc
Example #18
0
    def drawCorner(self, painter, position, cornerType, maxRadius=None):
        #logging.debug(self.__class__.__name__ +": drawCorner() "+ self.cornerTypeString(cornerType))
        thickness = self.CONNECTION_THICKNESS * self.zoomFactor()
        halfthick = thickness / 2
        cornerRoundness = halfthick ** 0.5
        cornerOffset = halfthick * (cornerRoundness)
        innerCorner = halfthick * (cornerRoundness - 1)
        outerCorner = halfthick * (cornerRoundness + 1)
        innerWidth = halfthick * (cornerRoundness - 1)
        radius = halfthick * (cornerRoundness + 1)
        if maxRadius:
            maxRadius = max(maxRadius, thickness)
            radius = min(radius, maxRadius)

        if cornerType == self.CornerType.TOP_RIGHT:
            startAngle = 0

            outerCorner = QPointF(position.x() + halfthick - 2 * radius, position.y() - halfthick)
            innerCorner = QPointF(outerCorner.x(), outerCorner.y() + (thickness))
            center = QPointF(outerCorner.x() + radius, outerCorner.y() + radius)
            
            outerRect = QRectF(outerCorner, QSizeF(2 * radius, 2 * radius))
            innerRect = QRectF(innerCorner, QSizeF((2 * radius - thickness), (2 * radius - thickness)))
            
            outerStart = QPointF(outerCorner.x() + 2 * radius, outerCorner.y() + (radius + halfthick))
            innerStart = QPointF(outerCorner.x() + (radius - halfthick), outerCorner.y())
            
        elif cornerType == self.CornerType.TOP_LEFT:
            startAngle = 90
            
            outerCorner = QPointF(position.x() - halfthick, position.y() - halfthick)
            innerCorner = QPointF(outerCorner.x() + (thickness), outerCorner.y() + (thickness))
            center = QPointF(outerCorner.x() + radius, outerCorner.y() + radius)
            
            outerRect = QRectF(outerCorner, QSizeF(2 * radius, 2 * radius))
            innerRect = QRectF(innerCorner, QSizeF((2 * radius - thickness), (2 * radius - thickness)))
            
            outerStart = QPointF(outerCorner.x() + (radius + halfthick), outerCorner.y())
            innerStart = QPointF(outerCorner.x(), outerCorner.y() + (radius + halfthick))
            
        elif cornerType == self.CornerType.BOTTOM_LEFT:
            startAngle = 180
            
            outerCorner = QPointF(position.x() - halfthick, position.y() + halfthick - 2 * radius)
            innerCorner = QPointF(outerCorner.x() + (thickness), outerCorner.y())
            center = QPointF(outerCorner.x() + radius, outerCorner.y() + radius)
            
            outerRect = QRectF(outerCorner, QSizeF(2 * radius, 2 * radius))
            innerRect = QRectF(innerCorner, QSizeF((2 * radius - thickness), (2 * radius - thickness)))
            
            outerStart = QPointF(outerCorner.x(), outerCorner.y() + (radius - halfthick))
            innerStart = QPointF(outerCorner.x() + (radius + halfthick), outerCorner.y() + (2 * radius))
            
        elif cornerType == self.CornerType.BOTTOM_RIGHT:
            startAngle = 270
            
            outerCorner = QPointF(position.x() + halfthick - 2 * radius, position.y() + halfthick - 2 * radius)
            innerCorner = QPointF(outerCorner.x(), outerCorner.y())
            center = QPointF(outerCorner.x() + radius, outerCorner.y() + radius)
            
            outerRect = QRectF(outerCorner, QSizeF(2 * radius, 2 * radius))
            innerRect = QRectF(innerCorner, QSizeF((2 * radius - thickness), (2 * radius - thickness)))
            
            outerStart = QPointF(outerCorner.x() + (radius - halfthick), outerCorner.y() + 2 * radius)
            innerStart = QPointF(outerCorner.x() + 2 * radius, outerCorner.y() + (radius - halfthick))
            
        else:
            # No defined corner, so nothing to draw.
            #print "PointToPointConnection.drawCorner() - No valid corner, aborting..."
            return
        
        if painter.redirected(painter.device()):
            # e.q. QPixmap.grabWidget()
            painter.setBrush(self.FILL_COLOR1)
        else:
            brush = QRadialGradient(center, radius)
            if radius >= thickness:
                brush.setColorAt((radius - thickness) / radius, self.FILL_COLOR1)   # inner border 
                brush.setColorAt((radius - halfthick + 1) / radius, self.FILL_COLOR2)   # center of line
            else:
                # If zoom is too small use single color
                brush.setColorAt(0, self.FILL_COLOR1)    
            brush.setColorAt(1, self.FILL_COLOR1)                                   # outer border
            painter.setBrush(brush)
        
        path = QPainterPath()
        path.moveTo(outerStart)
        path.arcTo(outerRect, startAngle, 90)
        path.lineTo(innerStart)
        path.arcTo(innerRect, startAngle + 90, - 90)
        path.closeSubpath()
            
        #painter.setPen(Qt.NoPen)
        painter.drawPath(path)
    def drawCyclePath(self, v1, sepInput, v2, sepOutput, delta, cl):
        """
        Tracé d'un arc reliant le noeud node1 à lui même dans le plan.
        Attention, puisque dans le plan de l'interface, l'axe des ordonnées est inveré,
        mais pas l'axe des abscisses la rotation dans le sens trigonométrique et le sens horaire sont inversés.
        """

        # Il est conseillé de prendre une feuille est un stylo pour dessiner en lisant les commentaires
        # de cette méthode

        # m1 et o sont des points définis plus loin, mais on peut calculer et on a besoin de calculer leur distance
        # dès maintenant
        m1omag = float(cl ** 2 - NodeItem.NodeWidth ** 2) / (2 * cl)

        # demi angle entre les tangentes de l'arc à ses deux extrêmités (entre l'arrivée et le départ).
        gamma = atan(m1omag / NodeItem.NodeWidth)

        # delta est l'angle qui existe entre l'horizontale est la droite coupant orthogonalement l'arc en son milieu
        u = Vector2(1, 0).rotate(delta)  # vecteur normé orienté du centre du noeud vers le milieu de l'arc
        # m1 est le point du cercle node1 au milieu du départ de l'arc
        v1m1norm = (u.rotate(-gamma))
        # m2 est la pointe de la flêche de l'arc
        v2m2norm = (u.rotate(gamma))

        v1m1 = NodeItem.NodeWidth * v1m1norm
        # Point sur le cercle node1 à une distance angulaire -alpha de m1
        m1m = v1 + v1m1.rotate(-ArcItem.endingsAlpha)
        # Point sur le cercle node1 à une distance angulaire alpha de m1
        m1p = v1 + v1m1.rotate(ArcItem.endingsAlpha)

        v2m2 = NodeItem.NodeWidth * v2m2norm
        m2 = v2 + v2m2  # Point m2
        a2 = v2 + 2 * v2m2  # a2 est le milieu du segment central de la pointe de la flêche de l'arc
        # a2m est l'extrêmité droite de la pointe de la flêche
        a2m = v2 + v2m2 + (NodeItem.NodeWidth / cos(ArcItem.arrowBeta)) * v2m2norm.rotate(-ArcItem.arrowBeta)
        # a2p est l'extrêmité gauche de la pointe de la flêche
        a2p = v2 + v2m2 + (NodeItem.NodeWidth / cos(ArcItem.arrowBeta)) * v2m2norm.rotate(ArcItem.arrowBeta)
        # m2m est le point sur le cercle node2 à une distance angulaire -alpha de m2
        v2m2m = v2m2.rotate(-ArcItem.endingsAlpha)  # Vecteur v2 m2m
        # m2p est le point sur le cercle node2 à une distance angulaire alpha de m2
        v2m2p = v2m2.rotate(ArcItem.endingsAlpha)  # Vecteur v2 m2p
        # m2mp est le point sur le segment central de la pointe de la flêche qui appartient à la droite passant
        # par m2m parallèle au vecteur v2m2, définit ici à l'aide d'un projeté orthogonal
        m2mp = a2 + v2m2m.project(a2m - a2)
        # m2pp est le point sur le segment central de la pointe de la flêche qui appartient à la droite passant
        # par m2p parallèle au vecteur v2m2, définit ici à l'aide d'un projeté orthogonal
        m2pp = a2 + v2m2p.project(a2p - a2)

        # o est le centre du cercle passant par les 3 points suivants : m1, m2 et c
        # où c est le point situé à une distance self.cl de v1, en suivant le vecteur u, cad le milieu de l'arc
        o = v1 + v1m1 + m1omag * v1m1norm.rotate(pi / 2)

        c1 = 0.5 * (m2pp + m1m)  # c1 est le milieu de m2pp et m1m
        # o1 est le centre du cercle passant par m1m et m2pp le plus proche de o
        o1 = c1 + (o - c1).project((m1m - m2pp).rotate(pi / 2))
        r1 = (o1 - m1m).magnitude()  # le rayon du cercle en question

        sinstang1 = Vector2(0, 1).dot(m1m - o1)  # sinus de l'angle entre l'horizontale et (o1,m1m)
        stang1 = -Vector2(1, 0).angle(m1m - o1)  # opposé de la valeur absolue de cet angle
        if sinstang1 < 0:
            stang1 *= -1
        sinendang1 = Vector2(0, 1).dot(m2pp - o1)  # sinus de l'angle entre l'horizontale et (o1,m2pp)
        endang1 = -Vector2(1, 0).angle(m2pp - o1)  # opposé de la valeur absolue de cet angle
        if sinendang1 < 0:
            endang1 *= -1
        pathang1 = endang1 - stang1
        while pathang1 > 0:  # correctifs pour afficher un bel arc de cercle dans le bon sens
            pathang1 -= 2 * pi
        while pathang1 < -2 * pi:
            pathang1 += 2 * pi

        c2 = 0.5 * (m2mp + m1p)  # c2 est le milieu de m2mp et m1p
        # o2 est le centre du cercle passant par m1p et m2mp le plus proche de o
        o2 = c2 + (o - c2).project((m1p - m2mp).rotate(pi / 2))
        r2 = (o2 - m1p).magnitude()  # le rayon du cercle en question
        sinstang2 = Vector2(0, 1).dot(m2mp - o2)  # sinus de l'angle entre l'horizontale et (o2,m2mp)
        stang2 = -Vector2(1, 0).angle(m2mp - o2)  # opposé de la valeur absolue de cet angle
        if sinstang2 < 0:
            stang2 *= -1
        sinendang2 = Vector2(0, 1).dot(m1p - o2)  # sinus de l'angle entre l'horizontale et (o2,m1p)
        endang2 = -Vector2(1, 0).angle(m1p - o2)  # opposé de la valeur absolue de cet angle
        if sinendang2 < 0:
            endang2 *= -1
        pathang2 = endang2 - stang2
        while pathang2 > 2 * pi:  # correctifs pour afficher un bel arc de cercle dans le bon sens
            pathang2 -= 2 * pi
        while pathang2 < 0:
            pathang2 += 2 * pi

        # Tracé du chemin
        path = QPainterPath()
        path.moveTo(m1m.x, m1m.y)
        path.arcTo(o1.x - r1, o1.y - r1, 2 * r1, 2 * r1, degrees(stang1), degrees(pathang1))
        path.lineTo(m2pp.x, m2pp.y)
        path.lineTo(m2mp.x, m2mp.y)
        path.arcTo(o2.x - r2, o2.y - r2, 2 * r2, 2 * r2, degrees(stang2), degrees(pathang2))
        path.lineTo(m1p.x, m1p.y)
        path.closeSubpath()
        path.moveTo(m2.x, m2.y)
        path.lineTo(a2p.x, a2p.y)
        path.lineTo(a2m.x, a2m.y)
        path.closeSubpath()
        self.setPath(path)

        textCenter = o  # v1 + cl * u
        labelItem = self.getLabelItem()
        labelItem.setArcVectorCenterAndOffset(u, textCenter, Vector2(0, 0))
    def drawClassicPath(self, v1, sepInput, v2, sepOutput, cl):
        """
        Trace d'un arc reliant les noeuds node1 et node2 dans le plan.
        Attention, puisque dans le plan de l'interface, l'axe des ordonnees est invere,
        mais pas l'axe des abscisses la rotation dans le sens trigonometrique et le sens horaire sont inverses.
        """

        # Il est conseille de prendre une feuille est un stylo pour dessiner en lisant les commentaires
        # de cette methode

        u = v2 - v1  # Vecteur reliant v1 à v2
        n = (u.rotate(pi / 2)).normalize()  # Vecteur unitaire perpendiculaire à u

        # Point sur la mediatrice de [v1,v2] situe a une distance cl
        # Il servira (presque) de point de controle pour les courbes de Beziers traçant les deux bords de l'arc.
        c = v1 + u / 2 + cl * n

        v1m1norm = (c - v1).normalize()  # Vecteur unitaire de la droite (v1,c), de v1 vers c
        v2m2norm = (c - v2).normalize()  # Vecteur unitaire de la droite (v2,c), de v2 vers c

        # m1 est le point du cercle node1 situé sur la droite (v1,c) entre ces deux points.
        # c'est également le milieu du départ de l'arc sur node1
        v1m1 = NodeItem.NodeWidth * v1m1norm  # Vecteur v1m1
        # Point sur le cercle node1 à une distance angulaire -alpha de m1
        m1m = v1 + v1m1.rotate(-ArcItem.endingsAlpha)
        # Point sur le cercle node1 à une distance angulaire alpha de m1
        m1p = v1 + v1m1.rotate(ArcItem.endingsAlpha)

        # m2 est le point du cercle node2 situé sur la droite (v2,c) entre ces deux points.
        # c'est également la pointe de la flêche de l'arc
        v2m2 = NodeItem.NodeWidth * v2m2norm  # Vecteur v2m2
        m2 = v2 + v2m2  # Point m2
        a2 = v2 + 2 * v2m2  # a2 est le milieu du segment central de la pointe de la flêche de l'arc
        # a2m est l'extrêmité droite de la pointe de la flêche
        a2m = v2 + v2m2 + (NodeItem.NodeWidth / cos(ArcItem.arrowBeta)) * v2m2norm.rotate(-ArcItem.arrowBeta)
        # a2p est l'extrêmité gauche de la pointe de la flêche
        a2p = v2 + v2m2 + (NodeItem.NodeWidth / cos(ArcItem.arrowBeta)) * v2m2norm.rotate(ArcItem.arrowBeta)
        # m2m est le point sur le cercle node2 à une distance angulaire -alpha de m2
        v2m2m = v2m2.rotate(-ArcItem.endingsAlpha)  # Vecteur v2 m2m
        # m2p est le point sur le cercle node2 à une distance angulaire alpha de m2
        v2m2p = v2m2.rotate(ArcItem.endingsAlpha)  # Vecteur v2 m2p
        # m2mp est le point sur le segment central de la pointe de la flêche qui appartient à la droite passant
        # par m2m parallèle au vecteur v2m2, définit ici à l'aide d'un projeté orthogonal
        m2mp = a2 + v2m2m.project(a2m - a2)
        # m2pp est le point sur le segment central de la pointe de la flêche qui appartient à la droite passant
        # par m2p parallèle au vecteur v2m2, définit ici à l'aide d'un projeté orthogonal
        m2pp = a2 + v2m2p.project(a2p - a2)

        w = (m1p - m1m).magnitude() / 2  # eviron la demi largeur de l'arc
        c1 = c - w * n  # point  de contrôle de la courbe de bézier du bord gauche de l'arc
        c2 = c + w * n  # point  de contrôle de la courbe de bézier du bord droit de l'arc

        # Tracé de l'arc
        path = QPainterPath()
        if sepInput:
            path.moveTo(v1.x + NodeItem.NodeWidth, v1.y)
            path.arcTo(v1.x - NodeItem.NodeWidth, v1.y - NodeItem.NodeWidth,
                           2 * NodeItem.NodeWidth, 2 * NodeItem.NodeWidth, 0, 360)
        path.moveTo(m1m.x, m1m.y)
        path.quadTo(c1.x, c1.y, m2pp.x, m2pp.y)
        path.lineTo(m2mp.x, m2mp.y)
        path.quadTo(c2.x, c2.y, m1p.x, m1p.y)
        path.closeSubpath()
        path.moveTo(m2.x, m2.y)
        path.lineTo(a2p.x, a2p.y)
        path.lineTo(a2m.x, a2m.y)
        path.closeSubpath()
        if sepOutput:
            path.moveTo(v2.x + NodeItem.NodeWidth, v2.y)
            path.arcTo(v2.x - NodeItem.NodeWidth, v2.y - NodeItem.NodeWidth,
                           2 * NodeItem.NodeWidth, 2 * NodeItem.NodeWidth, 0, 360)
        self.setPath(path)

        textCenter = v1 + u / 2  # position normale
        labelItem = self.getLabelItem()
        offset = 0.5 * cl * n
        labelItem.setArcVectorCenterAndOffset(u, textCenter, offset)
Example #21
0
def _generate_popup_path(rect, xRadius, yRadius, arrowSize, anchor):
    """ Generate the QPainterPath used to draw the outline of the popup.

    Parameters
    ----------
    rect : QRect
        Bounding rect for the popup.

    xRadius, yRadius : int
        x and y radius of the popup.

    arrowSize : QSize
        Width and height of the popup anchor arrow.

    anchor : int
        Positioning of the popup relative to the parent. Determines the
        position of the arrow.

    Returns
    -------
    result : QPainterPath
        Path that can be passed to QPainter.drawPath to render popup.

    """
    awidth, aheight = arrowSize.width(), arrowSize.height()
    draw_arrow = (awidth > 0 and aheight > 0)

    if anchor == QBubbleView.AnchorRight:
        rect.adjust(aheight, 0, 0, 0)
    elif anchor == QBubbleView.AnchorLeft:
        rect.adjust(0, 0, -aheight, 0)
    elif anchor == QBubbleView.AnchorBottom:
        rect.adjust(0, aheight, 0, 0)
    else:
        rect.adjust(0, 0, 0, -aheight)

    r = rect.normalized()

    if r.isNull():
        return

    hw = r.width() / 2
    hh = r.height() / 2

    xRadius = 100 * min(xRadius, hw) / hw
    yRadius = 100 * min(yRadius, hh) / hh

    # The starting point of the path is the top left corner
    x = r.x()
    y = r.y()
    w = r.width()
    h = r.height()
    rxx2 = w * xRadius / 100
    ryy2 = h * yRadius / 100

    center = r.center()

    path = QPainterPath()
    path.arcMoveTo(x, y, rxx2, ryy2, 180)
    path.arcTo(x, y, rxx2, ryy2, 180, -90)

    if anchor == QBubbleView.AnchorBottom and draw_arrow:
        path.lineTo(center.x() - awidth, y)
        path.lineTo(center.x(), y - aheight)
        path.lineTo(center.x() + awidth, y)

    path.arcTo(x + w - rxx2, y, rxx2, ryy2, 90, -90)

    if anchor == QBubbleView.AnchorLeft and draw_arrow:
        path.lineTo(x + w, center.y() - awidth)
        path.lineTo(x + w + aheight, center.y())
        path.lineTo(x + w, center.y() + awidth)

    path.arcTo(x + w - rxx2, y + h - ryy2, rxx2, ryy2, 0, -90)

    if anchor == QBubbleView.AnchorTop and draw_arrow:
        path.lineTo(center.x() + awidth, y + h)
        path.lineTo(center.x(), y + h + aheight)
        path.lineTo(center.x() - awidth, y + h)

    path.arcTo(x, y + h - ryy2, rxx2, ryy2, 270, -90)

    if anchor == QBubbleView.AnchorRight and draw_arrow:
        path.lineTo(x, center.y() + awidth)
        path.lineTo(x - aheight, center.y())
        path.lineTo(x, center.y() - awidth)

    path.closeSubpath()
    return path
Example #22
0
 def calculateDatasets(self, scene, axes, datasets):
     """
     Builds the datasets for this renderer.  Each renderer will need to
     subclass and implemenent this method, otherwise, no data will be
     shown in the chart.
     
     :param      scene | <XChartScene>
                 axes | [<
                 datasets | [<XChartDataset>, ..]
     """
     items = self.calculateDatasetItems(scene, datasets)
     if not items:
         scene.clear()
         return
     
     xaxis = scene.chart().horizontalAxis()
     yaxis = scene.chart().verticalAxis()
     data_axis = None
     all_values = []
     
     # determine if we're mapping data aginst the sets themselves, in
     # which case, create a pie chart of the dataset vs. its 
     if isinstance(xaxis, XDatasetAxis):
         per_dataset = False
         data_axis = yaxis
         total = 1
     
     elif isinstance(yaxis, XDatasetAxis):
         per_dataset = False
         total = 1
         data_axis = xaxis
     
     else:
         per_dataset = True
         total = len(items)
     
     if not per_dataset:
         all_values = [dataset.sum(data_axis) \
                       for dataset in datasets]
     
     # generate the build information
     rect = self.buildData('grid_rect')
     rect.setX(rect.x() + 10)
     rect.setY(rect.y() + 10)
     rect.setWidth(rect.width() - 20)
     rect.setHeight(rect.height() - 20)
     
     if rect.width() > rect.height():
         radius = min(rect.width() / 2.0, rect.height() / 2.0)
         x = rect.left()
         y = rect.top() + radius
         deltax = min(radius * 2, rect.width() / float(total + 1))
         deltay = 0
     else:
         radius = min(rect.height() / 2.0, rect.width() / 2.0)
         x = rect.left() + radius
         y = rect.top()
         deltax = 0
         deltay = min(radius * 2, rect.height() / float(total + 1))
     
     # initialize the first pie chart
     angle = 0
     cx = x + deltax
     cy = y + deltay
     
     x += deltax
     y += deltay
     
     for dataset in datasets:
         item = items.get(dataset)
         if not item:
             continue
         
         item.setBuildData('center', QPointF(cx, cy))
         item.setBuildData('radius', radius)
         
         subpaths = []
         bound = QRectF(cx-radius, cy-radius, radius * 2, radius * 2)
         path = QPainterPath()
         if per_dataset:
             data_values = dataset.values(yaxis.name())
             andle = 0
             for value in dataset.values():
                 perc = yaxis.percentOfTotal(value.get(yaxis.name()),
                                             data_values)
                 
                 # calculate the angle as the perc
                 item_angle = perc * 360
                 
                 subpath = QPainterPath()
                 subpath.moveTo(cx, cy)
                 subpath.arcTo(bound, angle, item_angle)
                 subpath.lineTo(cx, cy)
                 
                 path.addPath(subpath)
                 subpaths.append((value.get(xaxis.name()), subpath))
                 
                 angle += item_angle
                 
             cx = x + deltax
             cy = y + deltay
             
             x += deltax
             y += deltay
         else:
             value = dataset.sum(data_axis)
             perc = data_axis.percentOfTotal(value, all_values)
             
             # calculate the angle as the perc
             item_angle = perc * 360
             
             subpath = QPainterPath()
             subpath.moveTo(cx, cy)
             subpath.arcTo(bound, angle, item_angle)
             subpath.lineTo(cx, cy)
             
             path.addPath(subpath)
             subpaths.append((value, subpath))
             
             angle += item_angle
             
         item.setPath(path)
         item.setBuildData('subpaths', subpaths)
    def rebuild(self):
        """
        Rebuilds the item based on the current points.
        """
        scene = self.scene()
        if not scene:
            return

        self._subpaths = []

        grid = scene.gridRect()
        typ = self.chartType()

        hruler = scene.horizontalRuler()
        vruler = scene.verticalRuler()

        path = QPainterPath()
        area = QPainterPath()

        self._buildData.clear()
        self._buildData['path_area'] = area

        self.setPos(0, 0)

        # draw a line item
        if typ == XChartScene.Type.Line:
            first = True
            pos = None
            home = None
            self._ellipses = []

            points = self.points()
            if (self.orientation() == Qt.Horizontal):
                points.sort(hruler.compareValues, key=lambda x: x[0])
            else:
                points.sort(vruler.compareValues, key=lambda y: y[1])
                points.reverse()

            for x, y in self.points():
                pos = scene.mapFromChart(x, y)
                if first:
                    home = QPointF(pos.x(), grid.bottom())
                    area.moveTo(home)
                    area.lineTo(pos)
                    path.moveTo(pos)

                    self._ellipses.append(pos)

                    first = False
                else:
                    path.lineTo(pos)
                    area.lineTo(pos)

                    self._ellipses.append(pos)

            if pos and home:
                area.lineTo(pos.x(), grid.bottom())
                area.lineTo(home)

        # draw a bar item
        elif typ == XChartScene.Type.Bar:
            barsize = self.barSize()
            horiz = self.orientation() == Qt.Horizontal

            for x, y in self.points():
                pos = scene.mapFromChart(x, y)
                subpath = QPainterPath()
                if horiz:
                    r = min(grid.bottom() - pos.y(), 8)

                    subpath.moveTo(pos.x() - barsize / 2.0, grid.bottom())
                    subpath.lineTo(pos.x() - barsize / 2.0, pos.y() + r)
                    subpath.quadTo(pos.x() - barsize / 2.0, pos.y(),
                                   pos.x() - barsize / 2.0 + r, pos.y())

                    subpath.lineTo(pos.x() + barsize / 2.0 - r, pos.y())
                    subpath.quadTo(pos.x() + barsize / 2.0, pos.y(),
                                   pos.x() + barsize / 2.0,
                                   pos.y() + r)

                    subpath.lineTo(pos.x() + barsize / 2.0, grid.bottom())
                    subpath.lineTo(pos.x() - barsize / 2.0, grid.bottom())
                else:
                    subpath.moveTo(grid.left(), pos.y() - barsize / 2.0)
                    subpath.lineTo(pos.x(), pos.y() - barsize / 2.0)
                    subpath.lineTo(pos.x(), pos.y() + barsize / 2.0)
                    subpath.lineTo(grid.left(), pos.y() + barsize / 2.0)
                    subpath.lineTo(grid.left(), pos.y() - barsize / 2.0)

                path.addPath(subpath)
                self._subpaths.append((x, y, subpath))

        # draw a pie chart
        elif typ == XChartScene.Type.Pie:
            if self.orientation() == Qt.Horizontal:
                key_index = 0
                value_index = 1
                value_ruler = self.verticalRuler()
            else:
                key_index = 1
                value_index = 0
                value_ruler = self.horizontalRuler()

            pie_values = {}

            for point in self.points():
                key = point[key_index]
                value = point[value_index]

                pie_values.setdefault(key, [])
                pie_values[key].append(value)

            for key, values in pie_values.items():
                pie_values[key] = value_ruler.calcTotal(values)

            total = max(1, value_ruler.calcTotal(pie_values.values()))

            # calculate drawing parameters
            center = self.pieCenter()
            radius = self.radius()
            diameter = radius * 2
            angle = 0
            bound = QRectF(-radius, -radius, diameter, diameter)

            for key, value in sorted(pie_values.items(), key=lambda x: x[1]):
                # calculate the percentage
                perc = float(value) / total

                # calculate the angle as the perc * 360
                item_angle = perc * 360
                self.setPos(center)

                sub_path = QPainterPath()
                sub_path.arcTo(bound, angle, item_angle)
                sub_path.lineTo(0, 0)

                path.addPath(sub_path)
                self._subpaths.append((key, value, sub_path))

                angle += item_angle

        self.setPath(path)
        self._dirty = False
Example #24
0
    def _updatePP(self):
        """Create the neck geometry updating this item's QPainterPath.

        Return None.
        """
        self.prepareGeometryChange()
        pp = QPainterPath()
        stringSpan = (self.nStrings - 1) * self.stringSpacing
        nutWidth = stringSpan + self.stringEdgeOffset * 2
        # frets
        scaleLen = 25.5
        offset = 0.0            # previous fret x coordinate
        self.fretXs = [0.0]
        for n in range(self.nFrets):
            pos = offset + (scaleLen - offset) / 17.817
            self.fretXs.append(pos)
            pp.moveTo(pos, nutWidth)
            pp.lineTo(pos, 0.0)
            offset = pos
        # marker dots
        y = nutWidth / 2.0
        for n in [3, 5, 7, 9, 12, 15, 17, 19, 21, 24]:
            if n > self.nFrets:
                break
            fretX1 = self.fretXs[n-1]
            fretX2 = self.fretXs[n]
            x = fretX1 + (fretX2 - fretX1) / 2.0
            d = self.markerDia
            r = d / 2.0
            dy = nutWidth / 4.0
            if n % 12 == 0:
                pp.addEllipse(x-r, y-r-dy, d, d)
                pp.addEllipse(x-r, y-r+dy, d, d)
            else:
                pp.addEllipse(x-r, y-r, d, d)
        # strings
        self.stringYs = []
        endX = self.fretXs[-1]
        for n in range(self.nStrings):
            y = self.stringEdgeOffset + self.stringSpacing * n
            self.stringYs.append(y)
            pp.moveTo(-self.nutThickness - self.fretXs[1] / 2.0, y)
            pp.lineTo(endX, y)
        # outline
        pp.addRect(0, 0, self.fretXs[-1], nutWidth)
        # nut
        pp.addRect(-self.nutThickness, 0, self.nutThickness, nutWidth)
        # partial headstock, to allow room for open note display
        # upper curve
        r = 2.0
        d = self.fretXs[1] / 2.0
        rectL = -self.nutThickness - r
        rect = QRectF(rectL, -r*2.0, r*2.0, r*2.0)
        ra = asin(d / r)
        da = degrees(ra)
        pp.arcMoveTo(rect, 270.0)
        pp.arcTo(rect, 270.0, -da)
        # lower curve
        rect = QRectF(rectL, nutWidth, r*2.0, r*2.0)
        pp.arcMoveTo(rect, 90.0)
        pp.arcTo(rect, 90.0, da)
        # x coordinate of open string note markers
        self.openX = (-self.nutThickness - sin(ra) * r) / 2.0
        self.setPath(pp)
Example #25
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 = 0.5
        y = 0.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 = 0.5
            y = y + space + kw

        if ext_return:
            rx = rx * 2
            x1 = remaining_x[1]
            y1 = 0.5 + kw * 1 + space * 1
            w1 = remaining_widths[1]
            x2 = remaining_x[2]
            y2 = 0.5 + kw * 2 + space * 2
            w2 = remaining_widths[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 = 0.5 + kw * 2 + space * 2
            rect = QRectF(x, y, remaining_widths[2], kw)
            p.drawRoundedRect(rect, rx, rx)

        QWidget.paintEvent(self, pe)
Example #26
0
    def drawCorner(self, painter, position, cornerType, maxRadius=None):
        #logging.debug(self.__class__.__name__ +": drawCorner() "+ self.cornerTypeString(cornerType))
        thickness = self.CONNECTION_THICKNESS * self.zoomFactor()
        halfthick = thickness / 2
        cornerRoundness = halfthick**0.5
        cornerOffset = halfthick * (cornerRoundness)
        innerCorner = halfthick * (cornerRoundness - 1)
        outerCorner = halfthick * (cornerRoundness + 1)
        innerWidth = halfthick * (cornerRoundness - 1)
        radius = halfthick * (cornerRoundness + 1)
        if maxRadius:
            maxRadius = max(maxRadius, thickness)
            radius = min(radius, maxRadius)

        if cornerType == self.CornerType.TOP_RIGHT:
            startAngle = 0

            outerCorner = QPointF(position.x() + halfthick - 2 * radius,
                                  position.y() - halfthick)
            innerCorner = QPointF(outerCorner.x(),
                                  outerCorner.y() + (thickness))
            center = QPointF(outerCorner.x() + radius,
                             outerCorner.y() + radius)

            outerRect = QRectF(outerCorner, QSizeF(2 * radius, 2 * radius))
            innerRect = QRectF(
                innerCorner,
                QSizeF((2 * radius - thickness), (2 * radius - thickness)))

            outerStart = QPointF(outerCorner.x() + 2 * radius,
                                 outerCorner.y() + (radius + halfthick))
            innerStart = QPointF(outerCorner.x() + (radius - halfthick),
                                 outerCorner.y())

        elif cornerType == self.CornerType.TOP_LEFT:
            startAngle = 90

            outerCorner = QPointF(position.x() - halfthick,
                                  position.y() - halfthick)
            innerCorner = QPointF(outerCorner.x() + (thickness),
                                  outerCorner.y() + (thickness))
            center = QPointF(outerCorner.x() + radius,
                             outerCorner.y() + radius)

            outerRect = QRectF(outerCorner, QSizeF(2 * radius, 2 * radius))
            innerRect = QRectF(
                innerCorner,
                QSizeF((2 * radius - thickness), (2 * radius - thickness)))

            outerStart = QPointF(outerCorner.x() + (radius + halfthick),
                                 outerCorner.y())
            innerStart = QPointF(outerCorner.x(),
                                 outerCorner.y() + (radius + halfthick))

        elif cornerType == self.CornerType.BOTTOM_LEFT:
            startAngle = 180

            outerCorner = QPointF(position.x() - halfthick,
                                  position.y() + halfthick - 2 * radius)
            innerCorner = QPointF(outerCorner.x() + (thickness),
                                  outerCorner.y())
            center = QPointF(outerCorner.x() + radius,
                             outerCorner.y() + radius)

            outerRect = QRectF(outerCorner, QSizeF(2 * radius, 2 * radius))
            innerRect = QRectF(
                innerCorner,
                QSizeF((2 * radius - thickness), (2 * radius - thickness)))

            outerStart = QPointF(outerCorner.x(),
                                 outerCorner.y() + (radius - halfthick))
            innerStart = QPointF(outerCorner.x() + (radius + halfthick),
                                 outerCorner.y() + (2 * radius))

        elif cornerType == self.CornerType.BOTTOM_RIGHT:
            startAngle = 270

            outerCorner = QPointF(position.x() + halfthick - 2 * radius,
                                  position.y() + halfthick - 2 * radius)
            innerCorner = QPointF(outerCorner.x(), outerCorner.y())
            center = QPointF(outerCorner.x() + radius,
                             outerCorner.y() + radius)

            outerRect = QRectF(outerCorner, QSizeF(2 * radius, 2 * radius))
            innerRect = QRectF(
                innerCorner,
                QSizeF((2 * radius - thickness), (2 * radius - thickness)))

            outerStart = QPointF(outerCorner.x() + (radius - halfthick),
                                 outerCorner.y() + 2 * radius)
            innerStart = QPointF(outerCorner.x() + 2 * radius,
                                 outerCorner.y() + (radius - halfthick))

        else:
            # No defined corner, so nothing to draw.
            #print "PointToPointConnection.drawCorner() - No valid corner, aborting..."
            return

        if painter.redirected(painter.device()):
            # e.q. QPixmap.grabWidget()
            painter.setBrush(self.FILL_COLOR1)
        else:
            brush = QRadialGradient(center, radius)
            if radius >= thickness:
                brush.setColorAt((radius - thickness) / radius,
                                 self.FILL_COLOR1)  # inner border
                brush.setColorAt((radius - halfthick + 1) / radius,
                                 self.FILL_COLOR2)  # center of line
            else:
                # If zoom is too small use single color
                brush.setColorAt(0, self.FILL_COLOR1)
            brush.setColorAt(1, self.FILL_COLOR1)  # outer border
            painter.setBrush(brush)

        path = QPainterPath()
        path.moveTo(outerStart)
        path.arcTo(outerRect, startAngle, 90)
        path.lineTo(innerStart)
        path.arcTo(innerRect, startAngle + 90, -90)
        path.closeSubpath()

        #painter.setPen(Qt.NoPen)
        painter.drawPath(path)
Example #27
0
    def paintEvent(self, pe):
        p = QPainter(self)
        p.setRenderHint(QPainter.Antialiasing)

        # p.setBrush(QColor(0xf0, 0xf0, 0xf0)) # color of the border
        # p.drawRect(-1, -1, 800, 800)

        pen = QPen()
        pen.setWidth(1)
        pen.setColor(QColor(0x58, 0x58,
                            0x58))  # color of the borders of the keys
        p.setPen(pen)

        p.setBrush(QColor(0x58, 0x58, 0x58))  # color of the keys

        p.setBackgroundMode(Qt.TransparentMode)

        rx = 3

        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)

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

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

                p.setPen(QColor(0x9e, 0xde, 0x00))
                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 = 6
        y = 6

        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(6, y, first_key_w, kw)
                p.drawRoundedRect(rect, rx, rx)
                x = 6 + 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 = 6 + kw * 1 + space * 1
            w1 = remaining_widths[1]
            x2 = remaining_x[2]
            y2 = 6 + 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)
Example #28
0
    def calculateDatasets(self, scene, axes, datasets):
        """
        Builds the datasets for this renderer.  Each renderer will need to
        subclass and implemenent this method, otherwise, no data will be
        shown in the chart.
        
        :param      scene | <XChartScene>
                    axes | [<
                    datasets | [<XChartDataset>, ..]
        """
        items = self.calculateDatasetItems(scene, datasets)
        if not items:
            scene.clear()
            return

        xaxis = scene.chart().horizontalAxis()
        yaxis = scene.chart().verticalAxis()
        data_axis = None
        all_values = []

        # determine if we're mapping data aginst the sets themselves, in
        # which case, create a pie chart of the dataset vs. its
        if isinstance(xaxis, XDatasetAxis):
            per_dataset = False
            data_axis = yaxis
            total = 1

        elif isinstance(yaxis, XDatasetAxis):
            per_dataset = False
            total = 1
            data_axis = xaxis

        else:
            per_dataset = True
            total = len(items)

        if not per_dataset:
            all_values = [dataset.sum(data_axis) \
                          for dataset in datasets]

        # generate the build information
        rect = self.buildData('grid_rect')
        rect.setX(rect.x() + 10)
        rect.setY(rect.y() + 10)
        rect.setWidth(rect.width() - 20)
        rect.setHeight(rect.height() - 20)

        if rect.width() > rect.height():
            radius = min(rect.width() / 2.0, rect.height() / 2.0)
            x = rect.left()
            y = rect.top() + radius
            deltax = min(radius * 2, rect.width() / float(total + 1))
            deltay = 0
        else:
            radius = min(rect.height() / 2.0, rect.width() / 2.0)
            x = rect.left() + radius
            y = rect.top()
            deltax = 0
            deltay = min(radius * 2, rect.height() / float(total + 1))

        # initialize the first pie chart
        angle = 0
        cx = x + deltax
        cy = y + deltay

        x += deltax
        y += deltay

        for dataset in datasets:
            item = items.get(dataset)
            if not item:
                continue

            item.setBuildData('center', QPointF(cx, cy))
            item.setBuildData('radius', radius)

            subpaths = []
            bound = QRectF(cx - radius, cy - radius, radius * 2, radius * 2)
            path = QPainterPath()
            if per_dataset:
                data_values = dataset.values(yaxis.name())
                andle = 0
                for value in dataset.values():
                    perc = yaxis.percentOfTotal(value.get(yaxis.name()),
                                                data_values)

                    # calculate the angle as the perc
                    item_angle = perc * 360

                    subpath = QPainterPath()
                    subpath.moveTo(cx, cy)
                    subpath.arcTo(bound, angle, item_angle)
                    subpath.lineTo(cx, cy)

                    path.addPath(subpath)
                    subpaths.append((value.get(xaxis.name()), subpath))

                    angle += item_angle

                cx = x + deltax
                cy = y + deltay

                x += deltax
                y += deltay
            else:
                value = dataset.sum(data_axis)
                perc = data_axis.percentOfTotal(value, all_values)

                # calculate the angle as the perc
                item_angle = perc * 360

                subpath = QPainterPath()
                subpath.moveTo(cx, cy)
                subpath.arcTo(bound, angle, item_angle)
                subpath.lineTo(cx, cy)

                path.addPath(subpath)
                subpaths.append((value, subpath))

                angle += item_angle

            item.setPath(path)
            item.setBuildData('subpaths', subpaths)