Exemple #1
0
 def rebuild( self, gridRect ):
     """
     Rebuilds the tracker item.
     """
     scene = self.scene()
     if ( not scene ):
         return
     
     self.setVisible(gridRect.contains(self.pos()))
     self.setZValue(100)
     
     path = QPainterPath()
     path.moveTo(0, 0)
     path.lineTo(0, gridRect.height())
     
     tip             = ''
     tip_point       = None
     self._ellipses  = []
     items           = scene.collidingItems(self)
     self._basePath  = QPainterPath(path)
     
     for item in items:
         item_path = item.path()
         found = None
         for y in range(int(gridRect.top()), int(gridRect.bottom())):
             point = QPointF(self.pos().x(), y)
             if ( item_path.contains(point) ):
                 found = QPointF(0, y - self.pos().y())
                 break
         
         if ( found ):
             path.addEllipse(found, 6, 6)
             self._ellipses.append(found)
             
             # update the value information
             value     = scene.valueAt(self.mapToScene(found))
             tip_point = self.mapToScene(found)
             hruler    = scene.horizontalRuler()
             vruler    = scene.verticalRuler()
             
             x_value = hruler.formatValue(value[0])
             y_value = vruler.formatValue(value[1])
             
             tip = '<b>x:</b> %s<br/><b>y:</b> %s' % (x_value, y_value)
     
     self.setPath(path)
     self.setVisible(True)
     
     # show the popup widget
     if ( tip ):
         anchor    = XPopupWidget.Anchor.RightCenter
         widget    = self.scene().chartWidget()
         tip_point = widget.mapToGlobal(widget.mapFromScene(tip_point))
         
         XPopupWidget.showToolTip(tip, 
                                  anchor = anchor,
                                  parent = widget,
                                  point  = tip_point,
                                  foreground = QColor('blue'),
                                  background = QColor(148, 148, 255))
    def rebuild(self):
        """
        Rebuilds the dependency path for this item.
        """
        scene = self.scene()
        if (not scene):
            return

        sourcePos = self.sourceItem().viewItem().pos()
        sourceRect = self.sourceItem().viewItem().rect()

        targetPos = self.targetItem().viewItem().pos()
        targetRect = self.targetItem().viewItem().rect()

        cellWidth = scene.ganttWidget().cellWidth()

        startX = sourcePos.x() + sourceRect.width() - (cellWidth / 2.0)
        startY = sourcePos.y() + (sourceRect.height() / 2.0)

        endX = targetPos.x() - 2
        endY = targetPos.y() + (targetRect.height() / 2.0)

        path = QPainterPath()
        path.moveTo(startX, startY)
        path.lineTo(startX, endY)
        path.lineTo(endX, endY)

        a = QPointF(endX - 10, endY - 3)
        b = QPointF(endX, endY)
        c = QPointF(endX - 10, endY + 3)

        self._polygon = QPolygonF([a, b, c, a])

        path.addPolygon(self._polygon)

        self.setPath(path)
 def rebuild( self ):
     """
     Rebuilds the dependency path for this item.
     """
     scene      = self.scene()
     if ( not scene ):
         return
     
     sourcePos  = self.sourceItem().viewItem().pos()
     sourceRect = self.sourceItem().viewItem().rect()
     
     targetPos  = self.targetItem().viewItem().pos()
     targetRect = self.targetItem().viewItem().rect()
     
     cellWidth  = scene.ganttWidget().cellWidth()
     
     startX = sourcePos.x() + sourceRect.width() - (cellWidth / 2.0)
     startY = sourcePos.y() + (sourceRect.height() / 2.0)
     
     endX   = targetPos.x() - 2
     endY   = targetPos.y() + (targetRect.height() / 2.0)
     
     path = QPainterPath()
     path.moveTo(startX, startY)
     path.lineTo(startX, endY)
     path.lineTo(endX, endY)
     
     a = QPointF(endX - 10, endY - 3)
     b = QPointF(endX, endY)
     c = QPointF(endX - 10, endY + 3)
     
     self._polygon = QPolygonF([a, b, c, a])
     
     path.addPolygon(self._polygon)
     
     self.setPath(path)
Exemple #4
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
     
     rect = self.buildData('axis_rect')
     
     for dataset, item in items.items():
         first = True
         pos = None
         home = None
         ellipses = []
         
         path = QPainterPath()
         for value in dataset.values():
             pos = self.pointAt(axes, value)
             ellipses.append(pos)
             
             if first:
                 path.moveTo(pos)
                 first = False
             else:
                 path.lineTo(pos)
         
         item.setPath(path)
         item.setBuildData('ellipses', ellipses)
Exemple #5
0
 def borderPath(self):
     """
     Returns the border path that will be drawn for this widget.
     
     :return     <QPainterPath>
     """
     
     path = QPainterPath()
     
     x = 1
     y = 1
     w = self.width() - 2
     h = self.height() - 2
     pad = self.popupPadding()
     anchor = self.anchor()
     
     # create a path for a top-center based popup
     if anchor == XPopupWidget.Anchor.TopCenter:
         path.moveTo(x, y + pad)
         path.lineTo(x + ((w/2) - pad), y + pad)
         path.lineTo(x + (w/2), y)
         path.lineTo(x + ((w/2) + pad), y + pad)
         path.lineTo(x + w, y + pad)
         path.lineTo(x + w, y + h)
         path.lineTo(x, y + h)
         path.lineTo(x, y + pad)
     
     # create a path for a top-left based popup
     elif anchor == XPopupWidget.Anchor.TopLeft:
         path.moveTo(x, y + pad)
         path.lineTo(x + pad, y)
         path.lineTo(x + 2 * pad, y + pad)
         path.lineTo(x + w, y + pad)
         path.lineTo(x + w, y + h)
         path.lineTo(x, y + h)
         path.lineTo(x, y + pad)
     
     # create a path for a top-right based popup
     elif anchor == XPopupWidget.Anchor.TopRight:
         path.moveTo(x, y + pad)
         path.lineTo(x + w - 2 * pad, y + pad)
         path.lineTo(x + w - pad, y)
         path.lineTo(x + w, y + pad)
         path.lineTo(x + w, y + h)
         path.lineTo(x, y + h)
         path.lineTo(x, y + pad)
     
     # create a path for a bottom-left based popup
     elif anchor == XPopupWidget.Anchor.BottomLeft:
         path.moveTo(x, y)
         path.lineTo(x + w, y)
         path.lineTo(x + w, y + h - pad)
         path.lineTo(x + 2 * pad, y + h - pad)
         path.lineTo(x + pad, y + h)
         path.lineTo(x, y + h - pad)
         path.lineTo(x, y)
     
     # create a path for a south based popup
     elif anchor == XPopupWidget.Anchor.BottomCenter:
         path.moveTo(x, y)
         path.lineTo(x + w, y)
         path.lineTo(x + w, y + h - pad)
         path.lineTo(x + ((w/2) + pad), y + h - pad)
         path.lineTo(x + (w/2), y + h)
         path.lineTo(x + ((w/2) - pad), y + h - pad)
         path.lineTo(x, y + h - pad)
         path.lineTo(x, y)
     
     # create a path for a bottom-right based popup
     elif anchor == XPopupWidget.Anchor.BottomRight:
         path.moveTo(x, y)
         path.lineTo(x + w, y)
         path.lineTo(x + w, y + h - pad)
         path.lineTo(x + w - pad, y + h)
         path.lineTo(x + w - 2 * pad, y + h - pad)
         path.lineTo(x, y + h - pad)
         path.lineTo(x, y)
     
     # create a path for a right-top based popup
     elif anchor == XPopupWidget.Anchor.RightTop:
         path.moveTo(x, y)
         path.lineTo(x + w - pad, y)
         path.lineTo(x + w, y + pad)
         path.lineTo(x + w - pad, y + 2 * pad)
         path.lineTo(x + w - pad, y + h)
         path.lineTo(x, y + h)
         path.lineTo(x, y)
     
     # create a path for a right-center based popup
     elif anchor == XPopupWidget.Anchor.RightCenter:
         path.moveTo(x, y)
         path.lineTo(x + w - pad, y)
         path.lineTo(x + w - pad, y + ((h/2) - pad))
         path.lineTo(x + w, y + (h/2))
         path.lineTo(x + w - pad, y + ((h/2) + pad))
         path.lineTo(x + w - pad, y + h)
         path.lineTo(x, y + h)
         path.lineTo(x, y)
     
     # create a path for a right-bottom based popup
     elif anchor == XPopupWidget.Anchor.RightBottom:
         path.moveTo(x, y)
         path.lineTo(x + w - pad, y)
         path.lineTo(x + w - pad, y + h - 2 * pad)
         path.lineTo(x + w, y + h - pad)
         path.lineTo(x + w - pad, y + h)
         path.lineTo(x, y + h)
         path.lineTo(x, y)
     
     # create a path for a left-top based popup
     elif anchor == XPopupWidget.Anchor.LeftTop:
         path.moveTo(x + pad, y)
         path.lineTo(x + w, y)
         path.lineTo(x + w, y + h)
         path.lineTo(x + pad, y + h)
         path.lineTo(x + pad, y + 2 * pad)
         path.lineTo(x, y + pad)
         path.lineTo(x + pad, y)
     
     # create a path for an left-center based popup
     elif anchor == XPopupWidget.Anchor.LeftCenter:
         path.moveTo(x + pad, y)
         path.lineTo(x + w, y)
         path.lineTo(x + w, y + h)
         path.lineTo(x + pad, y + h)
         path.lineTo(x + pad, y + ((h/2) + pad))
         path.lineTo(x, y + (h/2))
         path.lineTo(x + pad, y + ((h/2) - pad))
         path.lineTo(x + pad, y)
     
     # create a path for a left-bottom based popup
     elif anchor == XPopupWidget.Anchor.LeftBottom:
         path.moveTo(x + pad, y)
         path.lineTo(x + w, y)
         path.lineTo(x + w, y + h)
         path.lineTo(x + pad, y + h)
         path.lineTo(x, y + h - pad)
         path.lineTo(x + pad, y + h - 2 * pad)
         path.lineTo(x + pad, y)
     
     return path
Exemple #6
0
    def rebuildMonth(self):
        """
        Rebuilds the current item in month mode.
        """
        scene = self.scene()
        if (not scene):
            return

        start_date = self.dateStart()
        end_date = self.dateEnd()
        min_date = scene.minimumDate()
        max_date = scene.maximumDate()

        # make sure our item is visible
        if (not (min_date <= end_date and start_date <= max_date)):
            self.hide()
            self.setPath(QPainterPath())
            return

        # make sure we have valid range information
        if (start_date < min_date):
            start_date = min_date
            start_inrange = False
        else:
            start_inrange = True

        if (max_date < end_date):
            end_date = max_date
            end_inrange = False
        else:
            end_inrange = True

        start_rect = scene.dateRect(start_date)
        end_rect = scene.dateRect(end_date)

        if (not (start_rect.isValid() and end_rect.isValid())):
            self.hide()
            return

        # rebuild an all day path
        path = QPainterPath()
        self.setPos(0, 0)

        pad = 2
        offset = 18
        height = 16

        min_left = 10
        max_right = scene.width() - 16
        delta_h = start_rect.height()

        # draw the all day event
        if (self.isAllDay()):
            top = start_rect.top()
            left = start_rect.left() + 3
            first = start_inrange

            while (top <= end_rect.top()):
                sub_path = QPainterPath()

                # calculate the end position
                if (end_rect.top() - 2 <= top and end_inrange):
                    at_end = True
                    right = end_rect.right() - pad
                else:
                    at_end = False
                    right = max_right

                if (first):
                    sub_path.moveTo(left, top + offset)
                    text_left = left + 4
                else:
                    sub_path.moveTo(left + height / 2, top + offset)
                    text_left = left + height / 2 + 2

                if (at_end):
                    sub_path.lineTo(right, top + offset)
                    sub_path.lineTo(right, top + offset + height)
                else:
                    sub_path.lineTo(right - height / 2, top + offset)
                    sub_path.lineTo(right, top + offset + height / 2)
                    sub_path.lineTo(right - height / 2, top + offset + height)

                if (first):
                    sub_path.lineTo(left, top + offset + height)
                    sub_path.lineTo(left, top + offset)
                else:
                    sub_path.lineTo(left + height / 2, top + offset + height)
                    sub_path.lineTo(left, top + offset + height / 2)
                    sub_path.lineTo(left + height / 2, top + offset)

                path.addPath(sub_path)

                data = (text_left, top + offset + 1, right, height,
                        Qt.AlignLeft | Qt.AlignVCenter, self.title())

                self._textData.append(data)

                left = min_left
                top += delta_h
                first = False
        else:
            text = '%s: (%s)' % (self.timeStart().toString('h:mm ap'),
                                 self.title())

            font = scene.font()
            left = start_rect.left() + 2 * pad
            top = start_rect.top() + offset

            path.addText(left, top + height / 2, font, text)

        # setup the path for this item
        self.setPath(path)
        self.show()

        # make sure there are no collisions
        while (self.collidingItems()):
            self.setPos(self.pos().x(), self.pos().y() + height + 2)

            # hide the item if out of the visible scope
            if (delta_h - offset <= self.pos().y() + height):
                self.hide()
                break
    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
 def rebuildDay( self ):
     """
     Rebuilds the current item in day mode.
     """
     scene = self.scene()
     if ( not scene ):
         return
     
     # calculate the base information
     start_date = self.dateStart()
     end_date   = self.dateEnd()
     min_date   = scene.minimumDate()
     max_date   = scene.maximumDate()
     
     # make sure our item is visible
     if ( not (min_date <= end_date and start_date <= max_date)):
         self.hide()
         self.setPath(QPainterPath())
         return
     
     # make sure we have valid range information
     if ( start_date < min_date ):
         start_date    = min_date
         start_inrange = False
     else:
         start_inrange = True
     
     if ( max_date < end_date ):
         end_date     = max_date
         end_inrange  = False
     else:
         end_inrange  = True
     
     # rebuild the path
     path = QPainterPath()
     self.setPos(0, 0)
     
     pad         = 2
     offset      = 18
     height      = 16
     
     # rebuild a timed item
     if ( not self.isAllDay() ):
         start_dtime = QDateTime(self.dateStart(), self.timeStart())
         end_dtime   = QDateTime(self.dateStart(), 
                                 self.timeEnd().addSecs(-30*60))
         
         start_rect  = scene.dateTimeRect(start_dtime)
         end_rect    = scene.dateTimeRect(end_dtime)
         
         left   = start_rect.left() + pad
         top    = start_rect.top() + pad
         right  = start_rect.right() - pad
         bottom = end_rect.bottom() - pad
         
         path.moveTo(left, top)
         path.lineTo(right, top)
         path.lineTo(right, bottom)
         path.lineTo(left, bottom)
         path.lineTo(left, top)
         
         data = (left + 6, 
                 top + 6, 
                 right - left - 12, 
                 bottom - top - 12,
                 Qt.AlignTop | Qt.AlignLeft,
                 '%s - %s\n(%s)' % (self.timeStart().toString('h:mmap')[:-1],
                                    self.timeEnd().toString('h:mmap'),
                                    self.title()))
         
         self._textData.append(data)
     
     self.setPath(path)
     self.show()
 def rebuildMonth( self ):
     """
     Rebuilds the current item in month mode.
     """
     scene = self.scene()
     if ( not scene ):
         return
     
     start_date  = self.dateStart()
     end_date    = self.dateEnd()
     min_date    = scene.minimumDate()
     max_date    = scene.maximumDate()
     
     # make sure our item is visible
     if ( not (min_date <= end_date and start_date <= max_date)):
         self.hide()
         self.setPath(QPainterPath())
         return
     
     # make sure we have valid range information
     if ( start_date < min_date ):
         start_date    = min_date
         start_inrange = False
     else:
         start_inrange = True
     
     if ( max_date < end_date ):
         end_date     = max_date
         end_inrange  = False
     else:
         end_inrange  = True
     
     start_rect = scene.dateRect(start_date)
     end_rect   = scene.dateRect(end_date)
     
     if ( not (start_rect.isValid() and end_rect.isValid()) ):
         self.hide()
         return
     
     # rebuild an all day path
     path = QPainterPath()
     self.setPos(0, 0)
     
     pad         = 2
     offset      = 18
     height      = 16
     
     min_left    = 10
     max_right   = scene.width() - 16
     delta_h     = start_rect.height()
     
     # draw the all day event
     if ( self.isAllDay() ):
         top   = start_rect.top()
         left  = start_rect.left() + 3
         first = start_inrange
         
         while ( top <= end_rect.top() ):
             sub_path  = QPainterPath()
             
             # calculate the end position
             if ( end_rect.top() - 2 <= top and end_inrange ):
                 at_end = True
                 right = end_rect.right() - pad
             else:
                 at_end = False
                 right = max_right
             
             if ( first ):
                 sub_path.moveTo(left, top + offset)
                 text_left = left + 4
             else:
                 sub_path.moveTo(left + height / 2, top + offset)
                 text_left = left + height / 2 + 2
             
             if ( at_end ):
                 sub_path.lineTo(right, top + offset)
                 sub_path.lineTo(right, top + offset + height)
             else:
                 sub_path.lineTo(right - height / 2, top + offset)
                 sub_path.lineTo(right, top + offset + height / 2)
                 sub_path.lineTo(right - height / 2, top + offset + height)
             
             if ( first ):
                 sub_path.lineTo(left, top + offset + height)
                 sub_path.lineTo(left, top + offset)
             else:
                 sub_path.lineTo(left + height / 2, top + offset + height)
                 sub_path.lineTo(left, top + offset + height / 2)
                 sub_path.lineTo(left + height / 2, top + offset)
             
             path.addPath(sub_path)
             
             data = (text_left,
                     top + offset + 1,
                     right,
                     height,
                     Qt.AlignLeft | Qt.AlignVCenter,
                     self.title())
             
             self._textData.append(data)
             
             left = min_left
             top += delta_h
             first = False
     else:
         text = '%s: (%s)' % (self.timeStart().toString('h:mm ap'), 
                              self.title())
         
         font   = scene.font()
         left   = start_rect.left() + 2 * pad
         top    = start_rect.top() + offset
         
         path.addText(left, top + height / 2, font, text)
     
     # setup the path for this item
     self.setPath(path)
     self.show()
     
     # make sure there are no collisions
     while ( self.collidingItems() ):
         self.setPos(self.pos().x(), self.pos().y() + height + 2)
         
         # hide the item if out of the visible scope
         if ( delta_h - offset <= self.pos().y() + height ):
             self.hide()
             break
Exemple #10
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

        rect = self.buildData('axis_rect')
        half_size = self.maximumBarSize() / 2.0

        for dataset, item in items.items():
            path = QPainterPath()
            subpaths = []

            for value in dataset.values():
                pos = self.pointAt(axes, value)

                radius = min(rect.bottom() - pos.y(), 8)

                subpath = QPainterPath()

                # create a vertical bar graph
                if self.orientation() == Qt.Vertical:
                    subpath.moveTo(pos.x() - half_size, rect.bottom())
                    subpath.lineTo(pos.x() - half_size, pos.y() + radius)
                    subpath.quadTo(pos.x() - half_size, pos.y(),
                                   pos.x() - half_size + radius, pos.y())
                    subpath.lineTo(pos.x() + half_size - radius, pos.y())
                    subpath.quadTo(pos.x() + half_size, pos.y(),
                                   pos.x() + half_size,
                                   pos.y() + radius)
                    subpath.lineTo(pos.x() + half_size, rect.bottom())
                    subpath.lineTo(pos.x() - half_size, rect.bottom())

                # create a horizontal bar graph
                else:
                    subpath.moveTo(rect.left(), pos.y() - half_size)
                    subpath.lineTo(pos.x(), pos.y() - half_size)
                    subpath.lineTo(pos.x(), pos.y() + half_size)
                    subpath.lineTo(rect.left(), pos.y() + half_size)
                    subpath.lineTo(rect.left(), pos.y() - half_size)

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

            item.setPath(path)
            item.setBuildData('subpaths', subpaths)
Exemple #11
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
     
     self.setBuildData('center', QPointF(cx, cy))
     self.setBuildData('radius', radius)
     
     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)
Exemple #12
0
    def borderPath(self):
        """
        Returns the border path that will be drawn for this widget.
        
        :return     <QPainterPath>
        """

        path = QPainterPath()

        x = 1
        y = 1
        w = self.width() - 2
        h = self.height() - 2
        pad = self.popupPadding()
        anchor = self.anchor()

        # create a path for a top-center based popup
        if anchor == XPopupWidget.Anchor.TopCenter:
            path.moveTo(x, y + pad)
            path.lineTo(x + ((w / 2) - pad), y + pad)
            path.lineTo(x + (w / 2), y)
            path.lineTo(x + ((w / 2) + pad), y + pad)
            path.lineTo(x + w, y + pad)
            path.lineTo(x + w, y + h)
            path.lineTo(x, y + h)
            path.lineTo(x, y + pad)

        # create a path for a top-left based popup
        elif anchor == XPopupWidget.Anchor.TopLeft:
            path.moveTo(x, y + pad)
            path.lineTo(x + pad, y)
            path.lineTo(x + 2 * pad, y + pad)
            path.lineTo(x + w, y + pad)
            path.lineTo(x + w, y + h)
            path.lineTo(x, y + h)
            path.lineTo(x, y + pad)

        # create a path for a top-right based popup
        elif anchor == XPopupWidget.Anchor.TopRight:
            path.moveTo(x, y + pad)
            path.lineTo(x + w - 2 * pad, y + pad)
            path.lineTo(x + w - pad, y)
            path.lineTo(x + w, y + pad)
            path.lineTo(x + w, y + h)
            path.lineTo(x, y + h)
            path.lineTo(x, y + pad)

        # create a path for a bottom-left based popup
        elif anchor == XPopupWidget.Anchor.BottomLeft:
            path.moveTo(x, y)
            path.lineTo(x + w, y)
            path.lineTo(x + w, y + h - pad)
            path.lineTo(x + 2 * pad, y + h - pad)
            path.lineTo(x + pad, y + h)
            path.lineTo(x, y + h - pad)
            path.lineTo(x, y)

        # create a path for a south based popup
        elif anchor == XPopupWidget.Anchor.BottomCenter:
            path.moveTo(x, y)
            path.lineTo(x + w, y)
            path.lineTo(x + w, y + h - pad)
            path.lineTo(x + ((w / 2) + pad), y + h - pad)
            path.lineTo(x + (w / 2), y + h)
            path.lineTo(x + ((w / 2) - pad), y + h - pad)
            path.lineTo(x, y + h - pad)
            path.lineTo(x, y)

        # create a path for a bottom-right based popup
        elif anchor == XPopupWidget.Anchor.BottomRight:
            path.moveTo(x, y)
            path.lineTo(x + w, y)
            path.lineTo(x + w, y + h - pad)
            path.lineTo(x + w - pad, y + h)
            path.lineTo(x + w - 2 * pad, y + h - pad)
            path.lineTo(x, y + h - pad)
            path.lineTo(x, y)

        # create a path for a right-top based popup
        elif anchor == XPopupWidget.Anchor.RightTop:
            path.moveTo(x, y)
            path.lineTo(x + w - pad, y)
            path.lineTo(x + w, y + pad)
            path.lineTo(x + w - pad, y + 2 * pad)
            path.lineTo(x + w - pad, y + h)
            path.lineTo(x, y + h)
            path.lineTo(x, y)

        # create a path for a right-center based popup
        elif anchor == XPopupWidget.Anchor.RightCenter:
            path.moveTo(x, y)
            path.lineTo(x + w - pad, y)
            path.lineTo(x + w - pad, y + ((h / 2) - pad))
            path.lineTo(x + w, y + (h / 2))
            path.lineTo(x + w - pad, y + ((h / 2) + pad))
            path.lineTo(x + w - pad, y + h)
            path.lineTo(x, y + h)
            path.lineTo(x, y)

        # create a path for a right-bottom based popup
        elif anchor == XPopupWidget.Anchor.RightBottom:
            path.moveTo(x, y)
            path.lineTo(x + w - pad, y)
            path.lineTo(x + w - pad, y + h - 2 * pad)
            path.lineTo(x + w, y + h - pad)
            path.lineTo(x + w - pad, y + h)
            path.lineTo(x, y + h)
            path.lineTo(x, y)

        # create a path for a left-top based popup
        elif anchor == XPopupWidget.Anchor.LeftTop:
            path.moveTo(x + pad, y)
            path.lineTo(x + w, y)
            path.lineTo(x + w, y + h)
            path.lineTo(x + pad, y + h)
            path.lineTo(x + pad, y + 2 * pad)
            path.lineTo(x, y + pad)
            path.lineTo(x + pad, y)

        # create a path for an left-center based popup
        elif anchor == XPopupWidget.Anchor.LeftCenter:
            path.moveTo(x + pad, y)
            path.lineTo(x + w, y)
            path.lineTo(x + w, y + h)
            path.lineTo(x + pad, y + h)
            path.lineTo(x + pad, y + ((h / 2) + pad))
            path.lineTo(x, y + (h / 2))
            path.lineTo(x + pad, y + ((h / 2) - pad))
            path.lineTo(x + pad, y)

        # create a path for a left-bottom based popup
        elif anchor == XPopupWidget.Anchor.LeftBottom:
            path.moveTo(x + pad, y)
            path.lineTo(x + w, y)
            path.lineTo(x + w, y + h)
            path.lineTo(x + pad, y + h)
            path.lineTo(x, y + h - pad)
            path.lineTo(x + pad, y + h - 2 * pad)
            path.lineTo(x + pad, y)

        return path
Exemple #13
0
    def rebuildDay(self):
        """
        Rebuilds the current item in day mode.
        """
        scene = self.scene()
        if (not scene):
            return

        # calculate the base information
        start_date = self.dateStart()
        end_date = self.dateEnd()
        min_date = scene.minimumDate()
        max_date = scene.maximumDate()

        # make sure our item is visible
        if (not (min_date <= end_date and start_date <= max_date)):
            self.hide()
            self.setPath(QPainterPath())
            return

        # make sure we have valid range information
        if (start_date < min_date):
            start_date = min_date
            start_inrange = False
        else:
            start_inrange = True

        if (max_date < end_date):
            end_date = max_date
            end_inrange = False
        else:
            end_inrange = True

        # rebuild the path
        path = QPainterPath()
        self.setPos(0, 0)

        pad = 2
        offset = 18
        height = 16

        # rebuild a timed item
        if (not self.isAllDay()):
            start_dtime = QDateTime(self.dateStart(), self.timeStart())
            end_dtime = QDateTime(self.dateStart(),
                                  self.timeEnd().addSecs(-30 * 60))

            start_rect = scene.dateTimeRect(start_dtime)
            end_rect = scene.dateTimeRect(end_dtime)

            left = start_rect.left() + pad
            top = start_rect.top() + pad
            right = start_rect.right() - pad
            bottom = end_rect.bottom() - pad

            path.moveTo(left, top)
            path.lineTo(right, top)
            path.lineTo(right, bottom)
            path.lineTo(left, bottom)
            path.lineTo(left, top)

            data = (left + 6, top + 6, right - left - 12, bottom - top - 12,
                    Qt.AlignTop | Qt.AlignLeft, '%s - %s\n(%s)' %
                    (self.timeStart().toString('h:mmap')[:-1],
                     self.timeEnd().toString('h:mmap'), self.title()))

            self._textData.append(data)

        self.setPath(path)
        self.show()
 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
 def paintMilestone( self, painter ):
     """
     Paints this item as the milestone look.
     
     :param      painter | <QPainter>
     """
     # generate the rect
     rect    = self.rect()
     
     padding = self.padding()
     gantt   = self.scene().ganttWidget()
     cell_w  = gantt.cellWidth()
     cell_h  = gantt.cellHeight()
     
     x       = rect.width() - cell_w
     y       = self.padding()
     w       = cell_w
     h       = rect.height() - padding - 2
     
     # grab the color options
     color       = self.color()
     alt_color   = self.alternateColor()
     
     if ( self.isSelected() ):
         color       = self.highlightColor()
         alt_color   = self.alternateHighlightColor()
     
     # create the background brush
     gradient = QLinearGradient()
     gradient.setStart(0, 0)
     gradient.setFinalStop(0, h)
     
     gradient.setColorAt(0,   color)
     gradient.setColorAt(0.8, alt_color)
     gradient.setColorAt(1,   color)
     
     painter.setPen(self.borderColor())
     painter.setBrush(QBrush(gradient))
     
     pen = painter.pen()
     pen.setWidthF(0.5)
     painter.setPen(pen)
     painter.setRenderHint( painter.Antialiasing )
     
     path = QPainterPath()
     path.moveTo(x - cell_w / 3.0, y + h / 2.0)
     path.lineTo(x, y)
     path.lineTo(x + cell_w / 3.0, y + h / 2.0)
     path.lineTo(x, y + h)
     path.lineTo(x - cell_w / 3.0, y + h / 2.0)
     
     painter.drawPath(path)
 def paintGroup( self, painter ):
     """
     Paints this item as the group look.
     
     :param      painter | <QPainter>
     """
     # generate the rect
     rect    = self.rect()
     
     padding = self.padding()
     gantt   = self.scene().ganttWidget()
     cell_w  = gantt.cellWidth()
     cell_h  = gantt.cellHeight()
     
     x       = 0
     y       = self.padding()
     w       = rect.width()
     h       = rect.height() - (padding + 1)
     
     # grab the color options
     color       = self.color()
     alt_color   = self.alternateColor()
     
     if ( self.isSelected() ):
         color       = self.highlightColor()
         alt_color   = self.alternateHighlightColor()
     
     # create the background brush
     gradient = QLinearGradient()
     gradient.setStart(0, 0)
     gradient.setFinalStop(0, h)
     
     gradient.setColorAt(0,   color)
     gradient.setColorAt(0.8, alt_color)
     gradient.setColorAt(1,   color)
     
     painter.setPen(self.borderColor())
     painter.setBrush(QBrush(gradient))
     
     pen = painter.pen()
     pen.setWidthF(0.5)
     painter.setPen(pen)
     painter.setRenderHint( painter.Antialiasing )
     
     path = QPainterPath()
     path.moveTo(x - cell_w / 4.0, y)
     path.lineTo(w + cell_w / 4.0, y)
     path.lineTo(w + cell_w / 4.0, y + h / 2.0)
     path.lineTo(w, h)
     path.lineTo(w - cell_w / 4.0, y + h / 2.0)
     path.lineTo(x + cell_w / 4.0, y + h / 2.0)
     path.lineTo(x, h)
     path.lineTo(x - cell_w / 4.0, y + h / 2.0)
     path.lineTo(x - cell_w / 4.0, y)
     
     painter.drawPath(path)
     
     # create the progress brush
     if ( self.showProgress() ):
         gradient = QLinearGradient()
         gradient.setStart(0, 0)
         gradient.setFinalStop(0, h)
         gradient.setColorAt(0, self.progressColor())
         gradient.setColorAt(0.8, self.alternateProgressColor())
         gradient.setColorAt(1, self.progressColor())
         
         prog_w = (w - 4) * (self._percentComplete/100.0)
         
         painter.setPen(Qt.NoPen)
         painter.setBrush(QBrush(gradient))
         painter.drawRect(x, y, prog_w, y + h / 2.0)
     
     # draw the text on this item
     if ( self.text() ):
         painter.setPen(self.textColor())
         painter.drawText(x, y, w, h, Qt.AlignCenter, self.text())
    def paintMilestone(self, painter):
        """
        Paints this item as the milestone look.
        
        :param      painter | <QPainter>
        """
        # generate the rect
        rect = self.rect()

        padding = self.padding()
        gantt = self.scene().ganttWidget()
        cell_w = gantt.cellWidth()
        cell_h = gantt.cellHeight()

        x = rect.width() - cell_w
        y = self.padding()
        w = cell_w
        h = rect.height() - padding - 2

        # grab the color options
        color = self.color()
        alt_color = self.alternateColor()

        if (self.isSelected()):
            color = self.highlightColor()
            alt_color = self.alternateHighlightColor()

        # create the background brush
        gradient = QLinearGradient()
        gradient.setStart(0, 0)
        gradient.setFinalStop(0, h)

        gradient.setColorAt(0, color)
        gradient.setColorAt(0.8, alt_color)
        gradient.setColorAt(1, color)

        painter.setPen(self.borderColor())
        painter.setBrush(QBrush(gradient))

        pen = painter.pen()
        pen.setWidthF(0.5)
        painter.setPen(pen)
        painter.setRenderHint(painter.Antialiasing)

        path = QPainterPath()
        path.moveTo(x - cell_w / 3.0, y + h / 2.0)
        path.lineTo(x, y)
        path.lineTo(x + cell_w / 3.0, y + h / 2.0)
        path.lineTo(x, y + h)
        path.lineTo(x - cell_w / 3.0, y + h / 2.0)

        painter.drawPath(path)
    def paintGroup(self, painter):
        """
        Paints this item as the group look.
        
        :param      painter | <QPainter>
        """
        # generate the rect
        rect = self.rect()

        padding = self.padding()
        gantt = self.scene().ganttWidget()
        cell_w = gantt.cellWidth()
        cell_h = gantt.cellHeight()

        x = 0
        y = self.padding()
        w = rect.width()
        h = rect.height() - (padding + 1)

        # grab the color options
        color = self.color()
        alt_color = self.alternateColor()

        if (self.isSelected()):
            color = self.highlightColor()
            alt_color = self.alternateHighlightColor()

        # create the background brush
        gradient = QLinearGradient()
        gradient.setStart(0, 0)
        gradient.setFinalStop(0, h)

        gradient.setColorAt(0, color)
        gradient.setColorAt(0.8, alt_color)
        gradient.setColorAt(1, color)

        painter.setPen(self.borderColor())
        painter.setBrush(QBrush(gradient))

        pen = painter.pen()
        pen.setWidthF(0.5)
        painter.setPen(pen)
        painter.setRenderHint(painter.Antialiasing)

        path = QPainterPath()
        path.moveTo(x - cell_w / 4.0, y)
        path.lineTo(w + cell_w / 4.0, y)
        path.lineTo(w + cell_w / 4.0, y + h / 2.0)
        path.lineTo(w, h)
        path.lineTo(w - cell_w / 4.0, y + h / 2.0)
        path.lineTo(x + cell_w / 4.0, y + h / 2.0)
        path.lineTo(x, h)
        path.lineTo(x - cell_w / 4.0, y + h / 2.0)
        path.lineTo(x - cell_w / 4.0, y)

        painter.drawPath(path)

        # create the progress brush
        if (self.showProgress()):
            gradient = QLinearGradient()
            gradient.setStart(0, 0)
            gradient.setFinalStop(0, h)
            gradient.setColorAt(0, self.progressColor())
            gradient.setColorAt(0.8, self.alternateProgressColor())
            gradient.setColorAt(1, self.progressColor())

            prog_w = (w - 4) * (self._percentComplete / 100.0)

            painter.setPen(Qt.NoPen)
            painter.setBrush(QBrush(gradient))
            painter.drawRect(x, y, prog_w, y + h / 2.0)

        # draw the text on this item
        if (self.text()):
            painter.setPen(self.textColor())
            painter.drawText(x, y, w, h, Qt.AlignCenter, self.text())
Exemple #19
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
     
     rect = self.buildData('axis_rect')
     half_size = self.maximumBarSize() / 2.0
     
     for dataset, item in items.items():
         path = QPainterPath()
         subpaths = []
         
         for value in dataset.values():
             pos = self.pointAt(axes, value)
             
             radius = min(rect.bottom() - pos.y(), 8)
             
             subpath = QPainterPath()
             
             # create a vertical bar graph
             if self.orientation() == Qt.Vertical:
                 subpath.moveTo(pos.x() - half_size, rect.bottom())
                 subpath.lineTo(pos.x() - half_size, pos.y() + radius)
                 subpath.quadTo(pos.x() - half_size, pos.y(),
                                pos.x() - half_size + radius, pos.y())
                 subpath.lineTo(pos.x() + half_size - radius, pos.y())
                 subpath.quadTo(pos.x() + half_size, pos.y(),
                                pos.x() + half_size, pos.y() + radius)
                 subpath.lineTo(pos.x() + half_size, rect.bottom())
                 subpath.lineTo(pos.x() - half_size, rect.bottom())
             
             # create a horizontal bar graph
             else:
                 subpath.moveTo(rect.left(), pos.y() - half_size)
                 subpath.lineTo(pos.x(),     pos.y() - half_size)
                 subpath.lineTo(pos.x(),     pos.y() + half_size)
                 subpath.lineTo(rect.left(), pos.y() + half_size)
                 subpath.lineTo(rect.left(), pos.y() - half_size)
             
             path.addPath(subpath)
             subpaths.append(subpath)
         
         item.setPath(path)
         item.setBuildData('subpaths', subpaths)
Exemple #20
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

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

        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)