def generateArrows(self):
     x, y = self.size().width() - 4, self.size().height() - 4
     pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.black))
     brush = QtGui.QBrush(pen.color().darker(150))
     points_list = [[
         QtCore.QPoint(x / 2, 0),
         QtCore.QPoint(x / 2 + 5, 5),
         QtCore.QPoint(x / 2 - 5, 5)
     ],
                    [
                        QtCore.QPoint(x / 2, y),
                        QtCore.QPoint(x / 2 + 5, y - 5),
                        QtCore.QPoint(x / 2 - 5, y - 5)
                    ],
                    [
                        QtCore.QPoint(0, y / 2),
                        QtCore.QPoint(5, y / 2 + 5),
                        QtCore.QPoint(5, y / 2 - 5)
                    ],
                    [
                        QtCore.QPoint(x, y / 2),
                        QtCore.QPoint(x - 5, y / 2 + 5),
                        QtCore.QPoint(x - 5, y / 2 - 5)
                    ]]
     for points in points_list:
         poly = QtGui.QPolygonF(points)
         path = QPainterPath()
         path.addPolygon(poly)
         self.rArrow = self.scene().addPolygon(poly, pen)
         self.scene().addPath(path, pen, brush)
Esempio n. 2
0
 def _paintPolygon(self, painter, polygon):
     path = QPainterPath()
     for line in polygon:
         ring = QPolygonF()
         for point in line:
             cur = self.toCanvasCoordinates(point) - self.pos()
             ring.append(cur)
         ring.append(ring[0])
         path.addPolygon(ring)
     painter.drawPath(path)
 def generateArrows(self):
     x, y = self.size().width()-4, self.size().height()-4
     pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.black))
     brush = QtGui.QBrush(pen.color().darker(150))
     points_list = [[QtCore.QPoint(x/2, 0), QtCore.QPoint(x/2 + 5, 5), QtCore.QPoint(x/2 - 5, 5)],
                    [QtCore.QPoint(x/2, y), QtCore.QPoint(x/2 + 5, y-5), QtCore.QPoint(x/2 - 5, y-5)],
                    [QtCore.QPoint(0, y/2), QtCore.QPoint(5,   y/2+5), QtCore.QPoint(5, y/2-5)],
                    [QtCore.QPoint(x, y/2), QtCore.QPoint(x-5, y/2+5), QtCore.QPoint(x-5, y/2-5)]]
     for points in points_list:
         poly = QtGui.QPolygonF(points)
         path = QPainterPath()
         path.addPolygon(poly)
         self.rArrow = self.scene().addPolygon(poly, pen)
         self.scene().addPath(path, pen, brush)
Esempio n. 4
0
    def updateShape(self, point=None, pos=None):
        # Main arrow direction
        params = parameters.instance
        scale = self.scale
        ms = min(scale)
        head_size = params.arrow_head_size * ms
        width = params.arrow_line_size * ms
        self.prepareGeometryChange()
        if point == self.source:
            p1 = pos
        else:
            p1 = self.source.pos()
        self.setPos(p1)
        if point == self.target:
            p2 = pos
        else:
            p2 = self.target.pos()
        tip = p2 - p1
        if abs(tip.x()) > 0.001 or abs(tip.y()) > 0.001:
            # Normalised
            #ntip = tip/stip
            ntip = tip
            # Arrow head base
            orth = QPointF(ntip.y(), -ntip.x()) * (head_size * 0.5)
            base_center = tip * (1 - 2 * head_size)
            base1 = base_center + orth
            base2 = base_center - orth
            base_center = tip * (1 - head_size * 1.50)
        else:
            ntip = tip
            base_center = tip
            base1 = tip
            base2 = tip

        self.tip = tip
        self.base_center = base_center
        self.base1 = base1
        self.base2 = base2

        path = QPainterPath()
        path.lineTo(base_center)
        path.addPolygon(QPolygonF([base_center, base1, tip, base2]))
        path.closeSubpath()
        self.rect = path.controlPointRect().adjusted(-width, -width, 2 * width,
                                                     2 * width)
        self.path = path
        self.update()
Esempio n. 5
0
def arrow_path_concave(line, width):
    """
    Return a :class:`QPainterPath` of a pretty looking arrow.
    """
    path = QPainterPath()
    p1, p2 = line.p1(), line.p2()

    if p1 == p2:
        return path

    baseline = QLineF(line)
    # Require some minimum length.
    baseline.setLength(max(line.length() - width * 3, width * 3))

    start, end = baseline.p1(), baseline.p2()
    mid = (start + end) / 2.0
    normal = QLineF.fromPolar(1.0, baseline.angle() + 90).p2()

    path.moveTo(start)
    path.lineTo(start + (normal * width / 4.0))

    path.quadTo(mid + (normal * width / 4.0),
                end + (normal * width / 1.5))

    path.lineTo(end - (normal * width / 1.5))
    path.quadTo(mid - (normal * width / 4.0),
                start - (normal * width / 4.0))
    path.closeSubpath()

    arrow_head_len = width * 4
    arrow_head_angle = 50
    line_angle = line.angle() - 180

    angle_1 = line_angle - arrow_head_angle / 2.0
    angle_2 = line_angle + arrow_head_angle / 2.0

    points = [p2,
              p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(),
              baseline.p2(),
              p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(),
              p2]

    poly = QPolygonF(points)
    path_head = QPainterPath()
    path_head.addPolygon(poly)
    path = path.united(path_head)
    return path
Esempio n. 6
0
    def updateShape(self, point=None, pos=None):
# Main arrow direction
        params = parameters.instance
        scale = self.scale
        ms = min(scale)
        head_size = params.arrow_head_size*ms
        width = params.arrow_line_size*ms
        self.prepareGeometryChange()
        if point == self.source:
            p1 = pos
        else:
            p1 = self.source.pos()
        self.setPos(p1)
        if point == self.target:
            p2 = pos
        else:
            p2 = self.target.pos()
        tip = p2-p1
        if abs(tip.x()) > 0.001 or abs(tip.y()) > 0.001:
# Normalised
            #ntip = tip/stip
            ntip = tip
# Arrow head base
            orth = QPointF(ntip.y(), -ntip.x())*(head_size*0.5)
            base_center = tip*(1-2*head_size)
            base1 = base_center + orth
            base2 = base_center - orth
            base_center = tip*(1-head_size*1.50)
        else:
            ntip = tip
            base_center = tip
            base1 = tip
            base2 = tip

        self.tip = tip
        self.base_center = base_center
        self.base1 = base1
        self.base2 = base2

        path = QPainterPath()
        path.lineTo(base_center)
        path.addPolygon(QPolygonF([base_center, base1, tip, base2]))
        path.closeSubpath()
        self.rect = path.controlPointRect().adjusted(-width, -width, 2*width, 2*width)
        self.path = path
        self.update()
Esempio n. 7
0
def arrow_path_concave(line, width):
    """
    Return a :class:`QPainterPath` of a pretty looking arrow.
    """
    path = QPainterPath()
    p1, p2 = line.p1(), line.p2()

    if p1 == p2:
        return path

    baseline = QLineF(line)
    # Require some minimum length.
    baseline.setLength(max(line.length() - width * 3, width * 3))

    start, end = baseline.p1(), baseline.p2()
    mid = (start + end) / 2.0
    normal = QLineF.fromPolar(1.0, baseline.angle() + 90).p2()

    path.moveTo(start)
    path.lineTo(start + (normal * width / 4.0))

    path.quadTo(mid + (normal * width / 4.0), end + (normal * width / 1.5))

    path.lineTo(end - (normal * width / 1.5))
    path.quadTo(mid - (normal * width / 4.0), start - (normal * width / 4.0))
    path.closeSubpath()

    arrow_head_len = width * 4
    arrow_head_angle = 50
    line_angle = line.angle() - 180

    angle_1 = line_angle - arrow_head_angle / 2.0
    angle_2 = line_angle + arrow_head_angle / 2.0

    points = [
        p2, p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(),
        baseline.p2(), p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(), p2
    ]

    poly = QPolygonF(points)
    path_head = QPainterPath()
    path_head.addPolygon(poly)
    path = path.united(path_head)
    return path
Esempio n. 8
0
def arrow_path_plain(line, width):
    """
    Return an :class:`QPainterPath` of a plain looking arrow.
    """
    path = QPainterPath()
    p1, p2 = line.p1(), line.p2()

    if p1 == p2:
        return path

    baseline = QLineF(line)
    # Require some minimum length.
    baseline.setLength(max(line.length() - width * 3, width * 3))
    path.moveTo(baseline.p1())
    path.lineTo(baseline.p2())

    stroker = QPainterPathStroker()
    stroker.setWidth(width)
    path = stroker.createStroke(path)

    arrow_head_len = width * 4
    arrow_head_angle = 50
    line_angle = line.angle() - 180

    angle_1 = line_angle - arrow_head_angle / 2.0
    angle_2 = line_angle + arrow_head_angle / 2.0

    points = [
        p2,
        p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(),
        p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(),
        p2,
    ]

    poly = QPolygonF(points)
    path_head = QPainterPath()
    path_head.addPolygon(poly)
    path = path.united(path_head)
    return path
Esempio n. 9
0
def arrow_path_plain(line, width):
    """
    Return an :class:`QPainterPath` of a plain looking arrow.
    """
    path = QPainterPath()
    p1, p2 = line.p1(), line.p2()

    if p1 == p2:
        return path

    baseline = QLineF(line)
    # Require some minimum length.
    baseline.setLength(max(line.length() - width * 3, width * 3))
    path.moveTo(baseline.p1())
    path.lineTo(baseline.p2())

    stroker = QPainterPathStroker()
    stroker.setWidth(width)
    path = stroker.createStroke(path)

    arrow_head_len = width * 4
    arrow_head_angle = 50
    line_angle = line.angle() - 180

    angle_1 = line_angle - arrow_head_angle / 2.0
    angle_2 = line_angle + arrow_head_angle / 2.0

    points = [
        p2, p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(),
        p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(), p2
    ]

    poly = QPolygonF(points)
    path_head = QPainterPath()
    path_head.addPolygon(poly)
    path = path.united(path_head)
    return path
Esempio n. 10
0
 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)
Esempio n. 11
0
 def shape(self):
     path = QPainterPath()
     path.addPolygon(
         EDraw.DefaultPolygon(self.boundingRect().width(),
                              self.boundingRect().height()))
     return path
Esempio n. 12
0
 def _write(self, shapes, svg_file, width, height, stroke_colour = None, stroke_width = None, background_colour = None):
 
     svg_file.write('<?xml version="1.0" standalone="no"?>\n'
                         '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"\n'
                         '  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n')
     
     svg_file.write('<svg width="%.6fcm" height="%.6fcm" ' % (width, height))
     svg_file.write('viewBox="%.6f %.6f %.6f %.6f" '
                         'xmlns="http://www.w3.org/2000/svg" '
                         'version="1.1">\n' % (0.0, 0.0, width, height))
     
     if stroke_width is None:
         stroke_width = "0.1%"
     
     if background_colour is not None:
     
         svg_file.write('<polygon fill="%s" ' % background_colour)
         svg_file.write('points="%.6f,%.6f %.6f,%.6f %.6f,%.6f %.6f,%.6f" />\n' % (
             0.0, 0.0, width, 0.0, width, height, 0.0, height))
     
     path = QPainterPath()
     shapes.reverse()
     
     new_shapes = {}
     
     for points, polygon in shapes:
     
         rgb = self.parts.colours.get(polygon.colour, "#ffffff")
         
         new_points = []
         for x, y in points:
             new_points.append(QPointF(x + width/2.0, height/2.0 - y))
         
         new_polygon = QPolygonF(new_points)
         new_path = QPainterPath()
         new_path.addPolygon(new_polygon)
         
         if path.contains(new_path):
             continue
         
         inter = path.intersected(new_path)
         remaining = new_path.subtracted(inter)
         
         # Combine the new path with the accumulated path and simplify
         # the result.
         path = path.united(new_path)
         path = path.simplified()
         
         piece_dict = new_shapes.setdefault(polygon.piece, {})
         colour_path = piece_dict.get(polygon.colour, QPainterPath())
         piece_dict[polygon.colour] = colour_path.united(remaining)
     
     for piece, piece_dict in new_shapes.items():
     
         svg_file.write('<g>\n')
         
         for colour, colour_path in piece_dict.items():
         
             if colour_path.isEmpty():
                 continue
             
             rgb = self.parts.colours.get(colour, "#ffffff")
             
             shape = '<path style="fill:%s; opacity:%f" d="' % (
                 rgb, self._opacity_from_colour(colour))
             
             i = 0
             in_path = False
             while i < colour_path.elementCount():
                 p = colour_path.elementAt(i)
                 if p.type == QPainterPath.MoveToElement:
                     if in_path:
                         shape += 'Z '
                     shape += 'M %.6f %.6f ' % (p.x, p.y)
                     in_path = True
                 elif p.type == QPainterPath.LineToElement:
                     shape += 'L %.6f %.6f ' % (p.x, p.y)
                 i += 1
             
             if in_path:
                 shape += 'Z'
             shape += '" />\n'
             
             svg_file.write(shape)
         
         svg_file.write('</g>\n')
     
     svg_file.write("</svg>\n")
     svg_file.close()
Esempio n. 13
0
    def setGeometry(self):
        """
        Read the parameters that define the geometry of the point
        """
        params = parameters.instance
        self.setEditable(params.is_cell_editable)
        points = self.points
        polygon_id = self.polygon_id
        polygon = [points[pt].pos() if pt in points else None for pt in polygon_id]
        non_none_cnt = len([p for p in polygon if p is not None])
        if non_none_cnt == 0:
            self.rect = QRectF()
            self.bounding_rect = QRectF()
            self.setVisible(False)
            return
        self.setVisible(True)
# First, check if this is a "simple" cell
        walls = self.walls
        real_polygon = [pid for pid in polygon_id if pid in points]
        #sides = [ walls[real_polygon[i], real_polygon[(i+1)%len(real_polygon)]] for i in range(len(real_polygon)) ]
        sides = [None] * len(polygon)
        self.sides = sides
        real_scale_x = self.scale[0]/self.glob_scale
        real_scale_y = self.scale[1]/self.glob_scale
        for i in range(len(polygon)):
            if polygon[i] is not None:  # Find the next
                j = (i+1) % len(polygon)
                while polygon[j] is None:
                    j = (j+1) % len(polygon)
                w = [QPointF(p.x()*real_scale_x, p.y()*real_scale_y) for p in walls[polygon_id[i], polygon_id[j]]]
                sides[i] = [polygon[i]] + w + [polygon[j]]
        prev = real_polygon[-1]
        polygon_shape = []
        for i in range(len(polygon)):
            if polygon[i]:
                polygon_shape.append(polygon[i])
                polygon_shape.extend(sides[i])
# Now add the dummy points .. starts at the first non-None point
        if non_none_cnt > 2:
            start = None
            for i in range(len(polygon)):
                if polygon[i] is not None:
                    start = i
                    break
            prev = start
            cur = start+1 if start+1 < len(polygon) else 0
            log_debug("Polygon before: [%s]" % ",".join("(%f,%f)" % (p.x(), p.y()) if p is not None else "None"
                                                        for p in polygon))
            while cur != start:
                if polygon[cur] is None:
                    cnt = 1
                    next = cur+1 if cur+1 < len(polygon) else 0
                    while True:
                        if polygon[next] is None:
                            cnt += 1
                        else:
                            break
                        next += 1
                        if next == len(polygon):
                            next = 0
                    #print "%d points missing" % cnt
                    # First, find total length of wall
                    length = 0.0
                    side = sides[prev]
                    for i in range(len(side)-1):
                        length += dist(side[i], side[i+1])
                    diff = length/(cnt+1)  # Distance between two points
                    i = cur
                    p = side[0]
                    for j in range(cnt):
                        l = 0.0
                        found = False
                        for k in range(len(side)-1):
                            dl = dist(side[k], side[k+1])
                            l += dl
                            if l > diff*(1+1e-5):  # Account for accumulation of small errors
                                c = (i + j) % len(polygon)
                                delta = diff-l+dl
                                p = side[k] + (side[k+1]-side[k])*delta/dl
                                s1 = side[:k+1] + [p]
                                s2 = [p] + side[k+1:]
                                sides[c-1] = s1
                                sides[c] = s2
                                side = s2
                                polygon[c] = p
                                found = True
                                break
                        assert found, "Could not find point in polygon for position %d" % (j+i,)
                        #p = p + diff
                        #c = (i+j)%len(polygon)
                        #polygon[c] = QPointF(p)
                    cur = next
                else:
                    prev = cur
                    cur += 1
                if cur >= len(polygon):
                    cur = 0
            assert None not in polygon, "Error, some dummy points were not added"
        else:
            polygon = [p for p in polygon if p is not None]
        center = sum(polygon, QPointF(0, 0)) / float(len(polygon))
        self.center = center
        if len(polygon) > 2:
            polygon = QPolygonF(polygon+[polygon[0]])
            polygon.translate(-center)
            polygon_shape = QPolygonF(polygon_shape + [polygon_shape[0]])
            self.polygon_shape = polygon_shape
            polygon_shape.translate(-center)
            # Translate the sides too
            sides = [[p-center for p in s] for s in sides]
            self.sides = sides
            assert len(sides) == len(polygon)-1
        elif len(polygon) == 2:
            polygon = QLineF(polygon[0], polygon[1])
            polygon.translate(-center)
        else:
            polygon = None
        self.polygon = polygon
        self.setPos(center)
        params = parameters.instance
        self.prepareGeometryChange()
        size = params.cell_size
        scale = self.scale
        height = size*cos(pi/6)*scale[1]
        width = size*scale[0]
        pos_x = size*cos(pi/3)*scale[0]
        self.sel_rect = QRectF(-width, -height, 2*width, 2*height)
        if isinstance(polygon, QPolygonF):
            self.rect = self.polygon_shape.boundingRect() | self.sel_rect
        elif isinstance(polygon, QLineF):
            self.rect = QRectF(polygon.p1(), polygon.p2()).normalized() | self.sel_rect
        else:
            self.rect = self.sel_rect
        self.bounding_rect = QRectF(self.rect)
        if self.p1 in points and self.p2 in points:
            self.division_line = QLineF(points[self.p1].pos()-center, points[self.p2].pos()-center)
        else:
            self.division_line = None
        self.hexagon = QPolygonF([QPointF(-width, 0), QPointF(-pos_x, height), QPointF(pos_x, height),
                                  QPointF(width, 0), QPointF(pos_x, -height), QPointF(-pos_x, -height)])
        self.hexagon_path = QPainterPath()
        self.hexagon_path.addPolygon(self.hexagon)
        s1 = QPainterPath()
        if isinstance(self.polygon, QPolygonF):
            s1.addPolygon(polygon_shape)
        elif isinstance(self.polygon, QLineF):
            s1.moveTo(self.polygon.p1())
            s1.lineTo(self.polygon.p2())
        stroke = QPainterPathStroker()
        sel_thick = 3*params.cell_thickness
        if sel_thick == 0:
            sel_thick = 3
        stroke.setWidth(sel_thick)
        self.stroke = stroke.createStroke(s1)
Esempio n. 14
0
    def paintEvent(self, event):
        option = QStyleOption()
        option.initFrom(self)

        contents_rect = self.style().subElementRect(QStyle.SE_FrameContents, option, self) or self.contentsRect() # the SE_FrameContents rect is Null unless the stylesheet defines decorations

        if self.graphStyle == self.BarStyle:
            graph_width = self.__dict__['graph_width'] = int(ceil(float(contents_rect.width()) / self.horizontalPixelsPerUnit))
        else:
            graph_width = self.__dict__['graph_width'] = int(ceil(float(contents_rect.width() - 1) / self.horizontalPixelsPerUnit) + 1)

        max_value = self.__dict__['max_value'] = max(chain([0], *(islice(reversed(graph.data), graph_width) for graph in self.graphs if graph.enabled)))

        if self.graphHeight == self.AutomaticHeight or self.graphHeight < 0:
            graph_height = self.__dict__['graph_height'] = max(self.scaler.get_height(max_value), self.minHeight)
        else:
            graph_height = self.__dict__['graph_height'] = max(self.graphHeight, self.minHeight)

        if self.graphStyle == self.BarStyle:
            height_scaling = float(contents_rect.height()) / graph_height
        else:
            height_scaling = float(contents_rect.height() - self.lineThickness) / graph_height

        painter = QStylePainter(self)
        painter.drawPrimitive(QStyle.PE_Widget, option)

        painter.setClipRect(contents_rect)

        painter.save()
        painter.translate(contents_rect.x() + contents_rect.width() - 1, contents_rect.y() + contents_rect.height() - 1)
        painter.scale(-1, -1)

        painter.setRenderHint(QStylePainter.Antialiasing, self.graphStyle != self.BarStyle)

        for graph in (graph for graph in self.graphs if graph.enabled and graph.data):
            if self.boundary is not None and 0 < self.boundary < graph_height:
                boundary_width = min(5.0/height_scaling, self.boundary-0, graph_height-self.boundary)
                pen_color = QLinearGradient(0, (self.boundary - boundary_width) * height_scaling, 0, (self.boundary + boundary_width) * height_scaling)
                pen_color.setColorAt(0, graph.color)
                pen_color.setColorAt(1, graph.over_boundary_color)
                brush_color = QLinearGradient(0, (self.boundary - boundary_width) * height_scaling, 0, (self.boundary + boundary_width) * height_scaling)
                brush_color.setColorAt(0, self.color_with_alpha(graph.color, self.fillTransparency))
                brush_color.setColorAt(1, self.color_with_alpha(graph.over_boundary_color, self.fillTransparency))
            else:
                pen_color = graph.color
                brush_color = self.color_with_alpha(graph.color, self.fillTransparency)
            dataset = islice(reversed(graph.data), graph_width)
            if self.graphStyle == self.BarStyle:
                lines = [QLine(x*self.horizontalPixelsPerUnit, 0, x*self.horizontalPixelsPerUnit, y*height_scaling) for x, y in enumerate(dataset)]
                painter.setPen(QPen(pen_color, self.lineThickness))
                painter.drawLines(lines)
            else:
                painter.translate(0, +self.lineThickness/2 - 1)

                if self.smoothEnvelope and self.smoothFactor > 0:
                    min_value = 0
                    max_value = graph_height * height_scaling
                    cx_offset = self.horizontalPixelsPerUnit / 3.0
                    smoothness = self.smoothFactor

                    last_values = deque(3*[dataset.next() * height_scaling], maxlen=3) # last 3 values: 0 last, 1 previous, 2 previous previous

                    envelope = QPainterPath()
                    envelope.moveTo(0, last_values[0])
                    for x, y in enumerate(dataset, 1):
                        x = x * self.horizontalPixelsPerUnit
                        y = y * height_scaling * (1 - smoothness) + last_values[0] * smoothness
                        last_values.appendleft(y)
                        c1x = x - cx_offset * 2
                        c2x = x - cx_offset
                        c1y = limit((1 + smoothness) * last_values[1] - smoothness * last_values[2], min_value, max_value) # same gradient as previous previous value to previous value
                        c2y = limit((1 - smoothness) * last_values[0] + smoothness * last_values[1], min_value, max_value) # same gradient as previous value to last value
                        envelope.cubicTo(c1x, c1y, c2x, c2y, x, y)
                else:
                    envelope = QPainterPath()
                    envelope.addPolygon(QPolygonF([QPointF(x*self.horizontalPixelsPerUnit, y*height_scaling) for x, y in enumerate(dataset)]))

                if self.fillEnvelope or graph.fill_envelope:
                    first_element = envelope.elementAt(0)
                    last_element = envelope.elementAt(envelope.elementCount() - 1)
                    fill_path = QPainterPath()
                    fill_path.moveTo(last_element.x, last_element.y)
                    fill_path.lineTo(last_element.x + 1, last_element.y)
                    fill_path.lineTo(last_element.x + 1, -self.lineThickness)
                    fill_path.lineTo(-self.lineThickness, -self.lineThickness)
                    fill_path.lineTo(-self.lineThickness, first_element.y)
                    fill_path.connectPath(envelope)
                    painter.fillPath(fill_path, brush_color)

                painter.strokePath(envelope, QPen(pen_color, self.lineThickness, join=Qt.RoundJoin))

                painter.translate(0, -self.lineThickness/2 + 1)

        if self.boundary is not None and self.boundaryColor:
            painter.setRenderHint(QStylePainter.Antialiasing, False)
            painter.setPen(QPen(self.boundaryColor, 1.0))
            painter.drawLine(0, self.boundary*height_scaling, contents_rect.width(), self.boundary*height_scaling)

        painter.restore()

        # queue the 'updated' signal to be emited after returning to the main loop
        QMetaObject.invokeMethod(self, 'updated', Qt.QueuedConnection)
Esempio n. 15
0
 def shape(self):
     path = QPainterPath()
     path.addPolygon( EDraw.DefaultPolygon( self.boundingRect().width(), self.boundingRect().height() ) )
     return path
Esempio n. 16
0
    def paintEvent(self, event):
        option = QStyleOption()
        option.initFrom(self)

        contents_rect = self.style().subElementRect(QStyle.SE_FrameContents, option, self) or self.contentsRect() # the SE_FrameContents rect is Null unless the stylesheet defines decorations

        if self.graphStyle == self.BarStyle:
            graph_width = self.__dict__['graph_width'] = int(ceil(float(contents_rect.width()) / self.horizontalPixelsPerUnit))
        else:
            graph_width = self.__dict__['graph_width'] = int(ceil(float(contents_rect.width() - 1) / self.horizontalPixelsPerUnit) + 1)

        max_value = self.__dict__['max_value'] = max(chain([0], *(islice(reversed(graph.data), graph_width) for graph in self.graphs if graph.enabled)))

        if self.graphHeight == self.AutomaticHeight or self.graphHeight < 0:
            graph_height = self.__dict__['graph_height'] = max(self.scaler.get_height(max_value), self.minHeight)
        else:
            graph_height = self.__dict__['graph_height'] = max(self.graphHeight, self.minHeight)

        if self.graphStyle == self.BarStyle:
            height_scaling = float(contents_rect.height()) / graph_height
        else:
            height_scaling = float(contents_rect.height() - self.lineThickness) / graph_height

        painter = QStylePainter(self)
        painter.drawPrimitive(QStyle.PE_Widget, option)

        painter.setClipRect(contents_rect)

        painter.save()
        painter.translate(contents_rect.x() + contents_rect.width() - 1, contents_rect.y() + contents_rect.height() - 1)
        painter.scale(-1, -1)

        painter.setRenderHint(QStylePainter.Antialiasing, self.graphStyle != self.BarStyle)

        for graph in (graph for graph in self.graphs if graph.enabled and graph.data):
            if self.boundary is not None and 0 < self.boundary < graph_height:
                boundary_width = min(5.0/height_scaling, self.boundary-0, graph_height-self.boundary)
                pen_color = QLinearGradient(0, (self.boundary - boundary_width) * height_scaling, 0, (self.boundary + boundary_width) * height_scaling)
                pen_color.setColorAt(0, graph.color)
                pen_color.setColorAt(1, graph.over_boundary_color)
                brush_color = QLinearGradient(0, (self.boundary - boundary_width) * height_scaling, 0, (self.boundary + boundary_width) * height_scaling)
                brush_color.setColorAt(0, self.color_with_alpha(graph.color, self.fillTransparency))
                brush_color.setColorAt(1, self.color_with_alpha(graph.over_boundary_color, self.fillTransparency))
            else:
                pen_color = graph.color
                brush_color = self.color_with_alpha(graph.color, self.fillTransparency)
            dataset = islice(reversed(graph.data), graph_width)
            if self.graphStyle == self.BarStyle:
                lines = [QLine(x*self.horizontalPixelsPerUnit, 0, x*self.horizontalPixelsPerUnit, y*height_scaling) for x, y in enumerate(dataset)]
                painter.setPen(QPen(pen_color, self.lineThickness))
                painter.drawLines(lines)
            else:
                painter.translate(0, +self.lineThickness/2 - 1)

                if self.smoothEnvelope and self.smoothFactor > 0:
                    min_value = 0
                    max_value = graph_height * height_scaling
                    cx_offset = self.horizontalPixelsPerUnit / 3.0
                    smoothness = self.smoothFactor

                    last_values = deque(3*[dataset.next() * height_scaling], maxlen=3) # last 3 values: 0 last, 1 previous, 2 previous previous

                    envelope = QPainterPath()
                    envelope.moveTo(0, last_values[0])
                    for x, y in enumerate(dataset, 1):
                        x = x * self.horizontalPixelsPerUnit
                        y = y * height_scaling * (1 - smoothness) + last_values[0] * smoothness
                        last_values.appendleft(y)
                        c1x = x - cx_offset * 2
                        c2x = x - cx_offset
                        c1y = limit((1 + smoothness) * last_values[1] - smoothness * last_values[2], min_value, max_value) # same gradient as previous previous value to previous value
                        c2y = limit((1 - smoothness) * last_values[0] + smoothness * last_values[1], min_value, max_value) # same gradient as previous value to last value
                        envelope.cubicTo(c1x, c1y, c2x, c2y, x, y)
                else:
                    envelope = QPainterPath()
                    envelope.addPolygon(QPolygonF([QPointF(x*self.horizontalPixelsPerUnit, y*height_scaling) for x, y in enumerate(dataset)]))

                if self.fillEnvelope or graph.fill_envelope:
                    first_element = envelope.elementAt(0)
                    last_element = envelope.elementAt(envelope.elementCount() - 1)
                    fill_path = QPainterPath()
                    fill_path.moveTo(last_element.x, last_element.y)
                    fill_path.lineTo(last_element.x + 1, last_element.y)
                    fill_path.lineTo(last_element.x + 1, -self.lineThickness)
                    fill_path.lineTo(-self.lineThickness, -self.lineThickness)
                    fill_path.lineTo(-self.lineThickness, first_element.y)
                    fill_path.connectPath(envelope)
                    painter.fillPath(fill_path, brush_color)

                painter.strokePath(envelope, QPen(pen_color, self.lineThickness, join=Qt.RoundJoin))

                painter.translate(0, -self.lineThickness/2 + 1)

        if self.boundary is not None and self.boundaryColor:
            painter.setRenderHint(QStylePainter.Antialiasing, False)
            painter.setPen(QPen(self.boundaryColor, 1.0))
            painter.drawLine(0, self.boundary*height_scaling, contents_rect.width(), self.boundary*height_scaling)

        painter.restore()

        # queue the 'updated' signal to be emited after returning to the main loop
        QMetaObject.invokeMethod(self, 'updated', Qt.QueuedConnection)
Esempio n. 17
0
class CellItem(QGraphicsItem):
    """
    Class representing a cell on the screen.

    :IVariables:
        cell_id : int
            Identifier of the cell
        hover : bool
            True if the cell is being hovered over
        hover_contour : bool
            True if the contour of the cell is being hovered over
        hover_side : int|None
            Number of the side being hovered over
        sides : list of `QPainterPath`
            shape of each side
        polygon_id : list of int
            list of point ids for the polygon
        walls : `TimedWallShapes`
            Ref to the structure defining the shape of the walls at the current time
        points : dict of int * QPointF
            Ref to the structure holding the position of all the points at the current time
        current : bool
            True if the cell is the currently selected one
        drag_line : bool
            True if one of the side is being dragged
        p1 : int
            Start of a division line
        p2 : int
            End of a division line
    """

    def __init__(self, scale, glob_scale, cell_id, polygon, points, walls, parent=None):
        QGraphicsItem.__init__(self, parent)
        self.cell_id = cell_id
        self.setZValue(2.5)
        self.setAcceptsHoverEvents(True)
        self.setSelectable(False)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.hover = False
        self.hover_contour = False
        self.hover_side = None
        self.scale = scale
        self.glob_scale = glob_scale
        self.setToolTip(unicode(cell_id))
        self.polygon_id = polygon
        self.walls = walls
        self.sides = []
        self.points = points
        self.current = False
        self.drag_line = False
        self.dragging_line = False
        self.editable = False
        self.p1 = None
        self.p2 = None
        self.setGeometry()

    def __del__(self):
        cleanQObject(self)

    def setCurrent(self, value=True):
        """
        Set this cell as the current one (i.e. on top and different color)
        """
        if value:
            self.setZValue(2.8)
        else:
            self.setZValue(2.5)
        self.current = value
        self.update()

    def setDivisionLine(self, p1, p2):
        """
        Set the line from p1 to p2 to be a division line (i.e. different representation)
        """
        self.p1 = p1
        self.p2 = p2
        self.setGeometry()

    def setGeometry(self):
        """
        Read the parameters that define the geometry of the point
        """
        params = parameters.instance
        self.setEditable(params.is_cell_editable)
        points = self.points
        polygon_id = self.polygon_id
        polygon = [points[pt].pos() if pt in points else None for pt in polygon_id]
        non_none_cnt = len([p for p in polygon if p is not None])
        if non_none_cnt == 0:
            self.rect = QRectF()
            self.bounding_rect = QRectF()
            self.setVisible(False)
            return
        self.setVisible(True)
# First, check if this is a "simple" cell
        walls = self.walls
        real_polygon = [pid for pid in polygon_id if pid in points]
        #sides = [ walls[real_polygon[i], real_polygon[(i+1)%len(real_polygon)]] for i in range(len(real_polygon)) ]
        sides = [None] * len(polygon)
        self.sides = sides
        real_scale_x = self.scale[0]/self.glob_scale
        real_scale_y = self.scale[1]/self.glob_scale
        for i in range(len(polygon)):
            if polygon[i] is not None:  # Find the next
                j = (i+1) % len(polygon)
                while polygon[j] is None:
                    j = (j+1) % len(polygon)
                w = [QPointF(p.x()*real_scale_x, p.y()*real_scale_y) for p in walls[polygon_id[i], polygon_id[j]]]
                sides[i] = [polygon[i]] + w + [polygon[j]]
        prev = real_polygon[-1]
        polygon_shape = []
        for i in range(len(polygon)):
            if polygon[i]:
                polygon_shape.append(polygon[i])
                polygon_shape.extend(sides[i])
# Now add the dummy points .. starts at the first non-None point
        if non_none_cnt > 2:
            start = None
            for i in range(len(polygon)):
                if polygon[i] is not None:
                    start = i
                    break
            prev = start
            cur = start+1 if start+1 < len(polygon) else 0
            log_debug("Polygon before: [%s]" % ",".join("(%f,%f)" % (p.x(), p.y()) if p is not None else "None"
                                                        for p in polygon))
            while cur != start:
                if polygon[cur] is None:
                    cnt = 1
                    next = cur+1 if cur+1 < len(polygon) else 0
                    while True:
                        if polygon[next] is None:
                            cnt += 1
                        else:
                            break
                        next += 1
                        if next == len(polygon):
                            next = 0
                    #print "%d points missing" % cnt
                    # First, find total length of wall
                    length = 0.0
                    side = sides[prev]
                    for i in range(len(side)-1):
                        length += dist(side[i], side[i+1])
                    diff = length/(cnt+1)  # Distance between two points
                    i = cur
                    p = side[0]
                    for j in range(cnt):
                        l = 0.0
                        found = False
                        for k in range(len(side)-1):
                            dl = dist(side[k], side[k+1])
                            l += dl
                            if l > diff*(1+1e-5):  # Account for accumulation of small errors
                                c = (i + j) % len(polygon)
                                delta = diff-l+dl
                                p = side[k] + (side[k+1]-side[k])*delta/dl
                                s1 = side[:k+1] + [p]
                                s2 = [p] + side[k+1:]
                                sides[c-1] = s1
                                sides[c] = s2
                                side = s2
                                polygon[c] = p
                                found = True
                                break
                        assert found, "Could not find point in polygon for position %d" % (j+i,)
                        #p = p + diff
                        #c = (i+j)%len(polygon)
                        #polygon[c] = QPointF(p)
                    cur = next
                else:
                    prev = cur
                    cur += 1
                if cur >= len(polygon):
                    cur = 0
            assert None not in polygon, "Error, some dummy points were not added"
        else:
            polygon = [p for p in polygon if p is not None]
        center = sum(polygon, QPointF(0, 0)) / float(len(polygon))
        self.center = center
        if len(polygon) > 2:
            polygon = QPolygonF(polygon+[polygon[0]])
            polygon.translate(-center)
            polygon_shape = QPolygonF(polygon_shape + [polygon_shape[0]])
            self.polygon_shape = polygon_shape
            polygon_shape.translate(-center)
            # Translate the sides too
            sides = [[p-center for p in s] for s in sides]
            self.sides = sides
            assert len(sides) == len(polygon)-1
        elif len(polygon) == 2:
            polygon = QLineF(polygon[0], polygon[1])
            polygon.translate(-center)
        else:
            polygon = None
        self.polygon = polygon
        self.setPos(center)
        params = parameters.instance
        self.prepareGeometryChange()
        size = params.cell_size
        scale = self.scale
        height = size*cos(pi/6)*scale[1]
        width = size*scale[0]
        pos_x = size*cos(pi/3)*scale[0]
        self.sel_rect = QRectF(-width, -height, 2*width, 2*height)
        if isinstance(polygon, QPolygonF):
            self.rect = self.polygon_shape.boundingRect() | self.sel_rect
        elif isinstance(polygon, QLineF):
            self.rect = QRectF(polygon.p1(), polygon.p2()).normalized() | self.sel_rect
        else:
            self.rect = self.sel_rect
        self.bounding_rect = QRectF(self.rect)
        if self.p1 in points and self.p2 in points:
            self.division_line = QLineF(points[self.p1].pos()-center, points[self.p2].pos()-center)
        else:
            self.division_line = None
        self.hexagon = QPolygonF([QPointF(-width, 0), QPointF(-pos_x, height), QPointF(pos_x, height),
                                  QPointF(width, 0), QPointF(pos_x, -height), QPointF(-pos_x, -height)])
        self.hexagon_path = QPainterPath()
        self.hexagon_path.addPolygon(self.hexagon)
        s1 = QPainterPath()
        if isinstance(self.polygon, QPolygonF):
            s1.addPolygon(polygon_shape)
        elif isinstance(self.polygon, QLineF):
            s1.moveTo(self.polygon.p1())
            s1.lineTo(self.polygon.p2())
        stroke = QPainterPathStroker()
        sel_thick = 3*params.cell_thickness
        if sel_thick == 0:
            sel_thick = 3
        stroke.setWidth(sel_thick)
        self.stroke = stroke.createStroke(s1)

    def changePoints(self, polygon):
        self.polygon_id = polygon
        self.setGeometry()

    def paint(self, painter, option, widget):
        params = parameters.instance
        pen = QPen(QColor(Qt.black))
        scale = self.scale
        ms = min(scale)
        pen.setWidth(params.cell_thickness)
        sel_thick = 2*params.cell_thickness
        if sel_thick == 0:
            sel_thick = 2*ms
        col = None
        if self.current:
            col = QColor(params.selected_cell_color)
        elif self.hover:
            col = QColor(params.cell_hover_color)
        else:
            col = QColor(params.cell_color)
        painter.setBrush(col)
        if self.hover_contour:
            pen1 = QPen(QColor(Qt.white))
            pen1.setWidth(sel_thick)
            painter.setPen(pen1)
        else:
            painter.setPen(pen)
        if isinstance(self.polygon, QPolygonF):
            painter.drawPolygon(self.polygon_shape)
        elif isinstance(self.polygon, QLineF):
            painter.drawLine(self.polygon)
        pen.setWidth(0)
        painter.setPen(pen)
        painter.drawPolygon(self.hexagon)
        if self.hover_side is not None:
            pen = QPen(QColor(Qt.red))
            pen.setWidth(sel_thick)
            side = self.sides[self.hover_side]
            painter.setPen(pen)
            pp = QPainterPath()
            pp.moveTo(side[0])
            for p in side[1:]:
                pp.lineTo(p)
            painter.drawPath(pp)
        elif self.division_line is not None:
            pen = QPen(params.division_wall_color)
            pen.setWidth(sel_thick)
            painter.setPen(pen)
            painter.drawLine(self.division_line)
        elif self.dragging_line:
            pen = QPen(QColor(Qt.red))
            pen.setWidth(sel_thick)
            painter.setPen(pen)
            polygon = self.polygon
            dg = self.drag_side
            p1 = polygon[dg]
            p2 = polygon[dg+1]
            painter.drawLine(p1, self.moving_point)
            painter.drawLine(self.moving_point, p2)

    def setEditable(self, value):
        self.editable = value

    def boundingRect(self):
        return self.bounding_rect

    def shape(self):
        """
        Returns the shape used for selection
        """
        s = QPainterPath()
        s.addPath(self.hexagon_path)
        if self.editable:
            s.addPath(self.stroke)
        return s

    def setSelectable(self, value=True):
        self.setFlag(QGraphicsItem.ItemIsSelectable, value)
        self.setFlag(QGraphicsItem.ItemIsMovable, True)

    def findClosestSide(self, pos):
        """
        Find the side of the polygon closest to pos
        """
        polygon = self.polygon
        min_dist = inf
        min_side = None
        if isinstance(polygon, QLineF):
            min_side = 0
            min_dist = 0
        else:
            #pos = pos + self.center
            sides = self.sides
            assert len(sides) == len(polygon)-1
            for i in range(len(polygon)-1):
                side = sides[i]
                d = distToPolyLine(pos,  side)
                if d < min_dist:
                    min_dist = d
                    min_side = i
        #print "Closest side found = %d, with distance = %f"%(min_side,  min_dist)
        return min_side, min_dist

    def findHover(self, pos):
        """
        Find which side is being hovered over
        """
        if self.editable:
            if self.drag_line:
                self.hover = False
                self.hover_side = None
                self.hover_contour = False
            elif self.hexagon_path.contains(pos):
                self.hover = True
                self.hover_side = None
                self.hover_contour = False
            else:
                params = parameters.instance
                sel_thick = 3*params.cell_thickness
                if sel_thick == 0:
                    sel_thick = 3
                self.hover_contour = True
                self.hover = False
                polygon = self.polygon
                if isinstance(polygon, QPolygonF):
                    min_side, min_dist = self.findClosestSide(pos)
                    #print "Closest side = %d"%min_side
                    if min_dist < sel_thick and min_side is not None:
                        self.hover_side = min_side
                    else:
                        self.hover_side = None
                        self.hover_contour = False
                        self.hover = True
        else:
            self.hover = True
            self.hover_side = None
            self.hover_contour = False

    def hoverEnterEvent(self, event):
        self.findHover(event.pos())
        self.update()

    def hoverMoveEvent(self, event):
        self.findHover(event.pos())
        self.update()

    def hoverLeaveEvent(self, event):
        self.hover = False
        self.hover_contour = False
        self.hover_side = None
        self.update()

    def mousePressEvent(self, event):
        if self.hover_side is not None:
            moving_point = QPointF(event.pos())
            self.drag_side = self.hover_side
            #self.polygon.insert(self.hover_side+1, moving_point)
            #self.sides[self.hover_side] = [self.polygon[self.hover_side], self.polygon[self.hover_side+1]]
            #self.sides.insert(self.hover_side+1, [self.polygon[self.hover_side+1], self.polygon[self.hover_side+2]])
            self.moving_point = moving_point
            self.start_drag = event.screenPos()
            self.hover_contour = False
            self.hover_side = None
            self.drag_line = True
            self.dragging_line = False
            self.update()
            event.accept()
        else:
            event.ignore()
            QGraphicsItem.mousePressEvent(self, event)

    def mouseMoveEvent(self, event):
        if not self.dragging_line and self.drag_line and (self.start_drag - event.screenPos()).manhattanLength() > 5:
            self.dragging_line = True
        if self.dragging_line:
            params = parameters.instance
            ms = min(self.scale)
            sel_thick = 2*params.cell_thickness
            if sel_thick == 0:
                sel_thick = 2*ms
            self.prepareGeometryChange()
            mp = self.moving_point
            mp.setX(event.pos().x())
            mp.setY(event.pos().y())
            self.bounding_rect = self.rect | QRectF(mp.x()-sel_thick,
                                                    mp.y()-sel_thick,
                                                    2*sel_thick,
                                                    2*sel_thick)
            self.update()

    def mouseReleaseEvent(self, event):
        if self.dragging_line:
            log_debug("Adding point to cell")
            self.setGeometry()
            drag_side = (self.drag_side+1) % (len(self.polygon)-1)
            self.scene().addPointToCell(self.cell_id, drag_side, self.mapToScene(event.pos()))
        else:
            event.ignore()
            QGraphicsItem.mouseReleaseEvent(self, event)
        self.drag_line = False
        self.dragging_line = False
Esempio n. 18
0
ppL5 = QPainterPath()  # Left 5' PainterPath
ppR5 = QPainterPath()  # Right 5' PainterPath
ppL3 = QPainterPath()  # Left 3' PainterPath
ppR3 = QPainterPath()  # Right 3' PainterPath
# set up ppL5 (left 5' blue square)
ppL5.addRect(0.25 * baseWidth, 0.125 * baseWidth,\
             0.75 * baseWidth, 0.75 * baseWidth)
# set up ppR5 (right 5' blue square)
ppR5.addRect(0, 0.125 * baseWidth,\
             0.75 * baseWidth, 0.75 * baseWidth)
# set up ppL3 (left 3' blue triangle)
l3poly = QPolygonF()
l3poly.append(QPointF(baseWidth, 0))
l3poly.append(QPointF(0.25 * baseWidth, 0.5 * baseWidth))
l3poly.append(QPointF(baseWidth, baseWidth))
ppL3.addPolygon(l3poly)
# set up ppR3 (right 3' blue triangle)
r3poly = QPolygonF()
r3poly.append(QPointF(0, 0))
r3poly.append(QPointF(0.75 * baseWidth, 0.5 * baseWidth))
r3poly.append(QPointF(0, baseWidth))
ppR3.addPolygon(r3poly)


class PathHelix(QGraphicsItem):
    """
    PathHelix is the primary "view" of the VirtualHelix data.
    It manages the ui interactions from the user, such as
    dragging breakpoints or crossovers addition/removal,
    and updates the data model accordingly.
Esempio n. 19
0
class Arrow(QGraphicsObject, QGraphicsItem):

    def __init__(self, x_offset, y_offset, parent=None):
        super(Arrow, self).__init__(parent=parent)
        self._parent = parent

        self.color = BLACK

        self.path = QPainterPath()
        self.setAcceptDrops(True)
        self.setAcceptHoverEvents(True)

        self.x_offset = x_offset
        self.y_offset = y_offset
        
#        self.rect = QRectF(x_offset + ARROW_BASE_X,
#                           y_offset - ARROW_HEIGHT,
#                           ARROW_WIDTH, ARROW_HEIGHT)
#        self.path.addRect(self.rect)
        self.setup_display()

    def setup_display(self):
        polygon = QPolygonF(
            [QPointF(self.x_offset + ARROW_BASE_X,                                          COMMIT_HEIGHT + ARROW_HEIGHT + self.y_offset),
             QPointF(self.x_offset + ARROW_BASE_X,                                          COMMIT_HEIGHT + ARROW_HEIGHT + self.y_offset - 20),
             QPointF(self.x_offset + ARROW_BASE_X - ARROW_TIP_WIDTH / 2,                    COMMIT_HEIGHT + ARROW_HEIGHT + self.y_offset - 19),
             QPointF(self.x_offset + ARROW_BASE_X + ARROW_BASE_WIDTH / 2,                   COMMIT_HEIGHT + ARROW_HEIGHT + self.y_offset - ARROW_HEIGHT),
             QPointF(self.x_offset + ARROW_BASE_X + ARROW_BASE_WIDTH + ARROW_TIP_WIDTH / 2, COMMIT_HEIGHT + ARROW_HEIGHT + self.y_offset - 19),
             QPointF(self.x_offset + ARROW_BASE_X + ARROW_BASE_WIDTH,                       COMMIT_HEIGHT + ARROW_HEIGHT + self.y_offset - 20),
             QPointF(self.x_offset + ARROW_BASE_X + ARROW_BASE_WIDTH,                       COMMIT_HEIGHT + ARROW_HEIGHT + self.y_offset), ]
        )
        self.path.addPolygon(polygon)
#    def hoverMoveEvent(self, event):
#        print "hover arrow move"
#
#    def hoverEnterEvent(self, event):
#        print "hover arrow enter"
#
#    def hoverLeaveEvent(self, event):
#        print "hover arrow leave"

    def dragEnterEvent(self, event):
        print "Enter"

    def dragLeaveEvent(self, event):
        print "Leave"

    def dragMoveEvent(self, event):
        print "Move"

    def dropEvent(self, event):
#        print dir(event.source())
#       print dir(event)
#        print dir(event.mimeData())
        # First string is commit hash, second is the branch
        self._parent.emit(SIGNAL("commitItemInserted(QString*, QString*)"),
                  QString(event.mimeData().text()), self._parent.branch)
        print "Drop"

    def paint(self, painter, option, widget=None):
        painter.setPen(Qt.NoPen)
        painter.setBrush(QBrush(self.color))
        painter.drawPath(self.path)

    def boundingRect(self):
        return self.path.boundingRect()

    def shape(self):
        return self.path
Esempio n. 20
0
class CellItem(QGraphicsItem):
    """
    Class representing a cell on the screen.

    :IVariables:
        cell_id : int
            Identifier of the cell
        hover : bool
            True if the cell is being hovered over
        hover_contour : bool
            True if the contour of the cell is being hovered over
        hover_side : int|None
            Number of the side being hovered over
        sides : list of `QPainterPath`
            shape of each side
        polygon_id : list of int
            list of point ids for the polygon
        walls : `TimedWallShapes`
            Ref to the structure defining the shape of the walls at the current time
        points : dict of int * QPointF
            Ref to the structure holding the position of all the points at the current time
        current : bool
            True if the cell is the currently selected one
        drag_line : bool
            True if one of the side is being dragged
        p1 : int
            Start of a division line
        p2 : int
            End of a division line
    """
    def __init__(self,
                 scale,
                 glob_scale,
                 cell_id,
                 polygon,
                 points,
                 walls,
                 parent=None):
        QGraphicsItem.__init__(self, parent)
        self.cell_id = cell_id
        self.setZValue(2.5)
        self.setAcceptsHoverEvents(True)
        self.setSelectable(False)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.hover = False
        self.hover_contour = False
        self.hover_side = None
        self.scale = scale
        self.glob_scale = glob_scale
        self.setToolTip(unicode(cell_id))
        self.polygon_id = polygon
        self.walls = walls
        self.sides = []
        self.points = points
        self.current = False
        self.drag_line = False
        self.dragging_line = False
        self.editable = False
        self.p1 = None
        self.p2 = None
        self.setGeometry()

    def __del__(self):
        cleanQObject(self)

    def setCurrent(self, value=True):
        """
        Set this cell as the current one (i.e. on top and different color)
        """
        if value:
            self.setZValue(2.8)
        else:
            self.setZValue(2.5)
        self.current = value
        self.update()

    def setDivisionLine(self, p1, p2):
        """
        Set the line from p1 to p2 to be a division line (i.e. different representation)
        """
        self.p1 = p1
        self.p2 = p2
        self.setGeometry()

    def setGeometry(self):
        """
        Read the parameters that define the geometry of the point
        """
        params = parameters.instance
        self.setEditable(params.is_cell_editable)
        points = self.points
        polygon_id = self.polygon_id
        polygon = [
            points[pt].pos() if pt in points else None for pt in polygon_id
        ]
        non_none_cnt = len([p for p in polygon if p is not None])
        if non_none_cnt == 0:
            self.rect = QRectF()
            self.bounding_rect = QRectF()
            self.setVisible(False)
            return
        self.setVisible(True)
        # First, check if this is a "simple" cell
        walls = self.walls
        real_polygon = [pid for pid in polygon_id if pid in points]
        #sides = [ walls[real_polygon[i], real_polygon[(i+1)%len(real_polygon)]] for i in range(len(real_polygon)) ]
        sides = [None] * len(polygon)
        self.sides = sides
        real_scale_x = self.scale[0] / self.glob_scale
        real_scale_y = self.scale[1] / self.glob_scale
        for i in range(len(polygon)):
            if polygon[i] is not None:  # Find the next
                j = (i + 1) % len(polygon)
                while polygon[j] is None:
                    j = (j + 1) % len(polygon)
                w = [
                    QPointF(p.x() * real_scale_x,
                            p.y() * real_scale_y)
                    for p in walls[polygon_id[i], polygon_id[j]]
                ]
                sides[i] = [polygon[i]] + w + [polygon[j]]
        prev = real_polygon[-1]
        polygon_shape = []
        for i in range(len(polygon)):
            if polygon[i]:
                polygon_shape.append(polygon[i])
                polygon_shape.extend(sides[i])
# Now add the dummy points .. starts at the first non-None point
        if non_none_cnt > 2:
            start = None
            for i in range(len(polygon)):
                if polygon[i] is not None:
                    start = i
                    break
            prev = start
            cur = start + 1 if start + 1 < len(polygon) else 0
            log_debug("Polygon before: [%s]" %
                      ",".join("(%f,%f)" %
                               (p.x(), p.y()) if p is not None else "None"
                               for p in polygon))
            while cur != start:
                if polygon[cur] is None:
                    cnt = 1
                    next = cur + 1 if cur + 1 < len(polygon) else 0
                    while True:
                        if polygon[next] is None:
                            cnt += 1
                        else:
                            break
                        next += 1
                        if next == len(polygon):
                            next = 0
                    #print "%d points missing" % cnt
                    # First, find total length of wall
                    length = 0.0
                    side = sides[prev]
                    for i in range(len(side) - 1):
                        length += dist(side[i], side[i + 1])
                    diff = length / (cnt + 1)  # Distance between two points
                    i = cur
                    p = side[0]
                    for j in range(cnt):
                        l = 0.0
                        found = False
                        for k in range(len(side) - 1):
                            dl = dist(side[k], side[k + 1])
                            l += dl
                            if l > diff * (
                                    1 + 1e-5
                            ):  # Account for accumulation of small errors
                                c = (i + j) % len(polygon)
                                delta = diff - l + dl
                                p = side[k] + (side[k + 1] -
                                               side[k]) * delta / dl
                                s1 = side[:k + 1] + [p]
                                s2 = [p] + side[k + 1:]
                                sides[c - 1] = s1
                                sides[c] = s2
                                side = s2
                                polygon[c] = p
                                found = True
                                break
                        assert found, "Could not find point in polygon for position %d" % (
                            j + i, )
                        #p = p + diff
                        #c = (i+j)%len(polygon)
                        #polygon[c] = QPointF(p)
                    cur = next
                else:
                    prev = cur
                    cur += 1
                if cur >= len(polygon):
                    cur = 0
            assert None not in polygon, "Error, some dummy points were not added"
        else:
            polygon = [p for p in polygon if p is not None]
        center = sum(polygon, QPointF(0, 0)) / float(len(polygon))
        self.center = center
        if len(polygon) > 2:
            polygon = QPolygonF(polygon + [polygon[0]])
            polygon.translate(-center)
            polygon_shape = QPolygonF(polygon_shape + [polygon_shape[0]])
            self.polygon_shape = polygon_shape
            polygon_shape.translate(-center)
            # Translate the sides too
            sides = [[p - center for p in s] for s in sides]
            self.sides = sides
            assert len(sides) == len(polygon) - 1
        elif len(polygon) == 2:
            polygon = QLineF(polygon[0], polygon[1])
            polygon.translate(-center)
        else:
            polygon = None
        self.polygon = polygon
        self.setPos(center)
        params = parameters.instance
        self.prepareGeometryChange()
        size = params.cell_size
        scale = self.scale
        height = size * cos(pi / 6) * scale[1]
        width = size * scale[0]
        pos_x = size * cos(pi / 3) * scale[0]
        self.sel_rect = QRectF(-width, -height, 2 * width, 2 * height)
        if isinstance(polygon, QPolygonF):
            self.rect = self.polygon_shape.boundingRect() | self.sel_rect
        elif isinstance(polygon, QLineF):
            self.rect = QRectF(polygon.p1(),
                               polygon.p2()).normalized() | self.sel_rect
        else:
            self.rect = self.sel_rect
        self.bounding_rect = QRectF(self.rect)
        if self.p1 in points and self.p2 in points:
            self.division_line = QLineF(points[self.p1].pos() - center,
                                        points[self.p2].pos() - center)
        else:
            self.division_line = None
        self.hexagon = QPolygonF([
            QPointF(-width, 0),
            QPointF(-pos_x, height),
            QPointF(pos_x, height),
            QPointF(width, 0),
            QPointF(pos_x, -height),
            QPointF(-pos_x, -height)
        ])
        self.hexagon_path = QPainterPath()
        self.hexagon_path.addPolygon(self.hexagon)
        s1 = QPainterPath()
        if isinstance(self.polygon, QPolygonF):
            s1.addPolygon(polygon_shape)
        elif isinstance(self.polygon, QLineF):
            s1.moveTo(self.polygon.p1())
            s1.lineTo(self.polygon.p2())
        stroke = QPainterPathStroker()
        sel_thick = 3 * params.cell_thickness
        if sel_thick == 0:
            sel_thick = 3
        stroke.setWidth(sel_thick)
        self.stroke = stroke.createStroke(s1)

    def changePoints(self, polygon):
        self.polygon_id = polygon
        self.setGeometry()

    def paint(self, painter, option, widget):
        params = parameters.instance
        pen = QPen(QColor(Qt.black))
        scale = self.scale
        ms = min(scale)
        pen.setWidth(params.cell_thickness)
        sel_thick = 2 * params.cell_thickness
        if sel_thick == 0:
            sel_thick = 2 * ms
        col = None
        if self.current:
            col = QColor(params.selected_cell_color)
        elif self.hover:
            col = QColor(params.cell_hover_color)
        else:
            col = QColor(params.cell_color)
        painter.setBrush(col)
        if self.hover_contour:
            pen1 = QPen(QColor(Qt.white))
            pen1.setWidth(sel_thick)
            painter.setPen(pen1)
        else:
            painter.setPen(pen)
        if isinstance(self.polygon, QPolygonF):
            painter.drawPolygon(self.polygon_shape)
        elif isinstance(self.polygon, QLineF):
            painter.drawLine(self.polygon)
        pen.setWidth(0)
        painter.setPen(pen)
        painter.drawPolygon(self.hexagon)
        if self.hover_side is not None:
            pen = QPen(QColor(Qt.red))
            pen.setWidth(sel_thick)
            side = self.sides[self.hover_side]
            painter.setPen(pen)
            pp = QPainterPath()
            pp.moveTo(side[0])
            for p in side[1:]:
                pp.lineTo(p)
            painter.drawPath(pp)
        elif self.division_line is not None:
            pen = QPen(params.division_wall_color)
            pen.setWidth(sel_thick)
            painter.setPen(pen)
            painter.drawLine(self.division_line)
        elif self.dragging_line:
            pen = QPen(QColor(Qt.red))
            pen.setWidth(sel_thick)
            painter.setPen(pen)
            polygon = self.polygon
            dg = self.drag_side
            p1 = polygon[dg]
            p2 = polygon[dg + 1]
            painter.drawLine(p1, self.moving_point)
            painter.drawLine(self.moving_point, p2)

    def setEditable(self, value):
        self.editable = value

    def boundingRect(self):
        return self.bounding_rect

    def shape(self):
        """
        Returns the shape used for selection
        """
        s = QPainterPath()
        s.addPath(self.hexagon_path)
        if self.editable:
            s.addPath(self.stroke)
        return s

    def setSelectable(self, value=True):
        self.setFlag(QGraphicsItem.ItemIsSelectable, value)
        self.setFlag(QGraphicsItem.ItemIsMovable, True)

    def findClosestSide(self, pos):
        """
        Find the side of the polygon closest to pos
        """
        polygon = self.polygon
        min_dist = inf
        min_side = None
        if isinstance(polygon, QLineF):
            min_side = 0
            min_dist = 0
        else:
            #pos = pos + self.center
            sides = self.sides
            assert len(sides) == len(polygon) - 1
            for i in range(len(polygon) - 1):
                side = sides[i]
                d = distToPolyLine(pos, side)
                if d < min_dist:
                    min_dist = d
                    min_side = i
        #print "Closest side found = %d, with distance = %f"%(min_side,  min_dist)
        return min_side, min_dist

    def findHover(self, pos):
        """
        Find which side is being hovered over
        """
        if self.editable:
            if self.drag_line:
                self.hover = False
                self.hover_side = None
                self.hover_contour = False
            elif self.hexagon_path.contains(pos):
                self.hover = True
                self.hover_side = None
                self.hover_contour = False
            else:
                params = parameters.instance
                sel_thick = 3 * params.cell_thickness
                if sel_thick == 0:
                    sel_thick = 3
                self.hover_contour = True
                self.hover = False
                polygon = self.polygon
                if isinstance(polygon, QPolygonF):
                    min_side, min_dist = self.findClosestSide(pos)
                    #print "Closest side = %d"%min_side
                    if min_dist < sel_thick and min_side is not None:
                        self.hover_side = min_side
                    else:
                        self.hover_side = None
                        self.hover_contour = False
                        self.hover = True
        else:
            self.hover = True
            self.hover_side = None
            self.hover_contour = False

    def hoverEnterEvent(self, event):
        self.findHover(event.pos())
        self.update()

    def hoverMoveEvent(self, event):
        self.findHover(event.pos())
        self.update()

    def hoverLeaveEvent(self, event):
        self.hover = False
        self.hover_contour = False
        self.hover_side = None
        self.update()

    def mousePressEvent(self, event):
        if self.hover_side is not None:
            moving_point = QPointF(event.pos())
            self.drag_side = self.hover_side
            #self.polygon.insert(self.hover_side+1, moving_point)
            #self.sides[self.hover_side] = [self.polygon[self.hover_side], self.polygon[self.hover_side+1]]
            #self.sides.insert(self.hover_side+1, [self.polygon[self.hover_side+1], self.polygon[self.hover_side+2]])
            self.moving_point = moving_point
            self.start_drag = event.screenPos()
            self.hover_contour = False
            self.hover_side = None
            self.drag_line = True
            self.dragging_line = False
            self.update()
            event.accept()
        else:
            event.ignore()
            QGraphicsItem.mousePressEvent(self, event)

    def mouseMoveEvent(self, event):
        if not self.dragging_line and self.drag_line and (
                self.start_drag - event.screenPos()).manhattanLength() > 5:
            self.dragging_line = True
        if self.dragging_line:
            params = parameters.instance
            ms = min(self.scale)
            sel_thick = 2 * params.cell_thickness
            if sel_thick == 0:
                sel_thick = 2 * ms
            self.prepareGeometryChange()
            mp = self.moving_point
            mp.setX(event.pos().x())
            mp.setY(event.pos().y())
            self.bounding_rect = self.rect | QRectF(
                mp.x() - sel_thick,
                mp.y() - sel_thick, 2 * sel_thick, 2 * sel_thick)
            self.update()

    def mouseReleaseEvent(self, event):
        if self.dragging_line:
            log_debug("Adding point to cell")
            self.setGeometry()
            drag_side = (self.drag_side + 1) % (len(self.polygon) - 1)
            self.scene().addPointToCell(self.cell_id, drag_side,
                                        self.mapToScene(event.pos()))
        else:
            event.ignore()
            QGraphicsItem.mouseReleaseEvent(self, event)
        self.drag_line = False
        self.dragging_line = False
Esempio n. 21
0
    def setGeometry(self):
        """
        Read the parameters that define the geometry of the point
        """
        params = parameters.instance
        self.setEditable(params.is_cell_editable)
        points = self.points
        polygon_id = self.polygon_id
        polygon = [
            points[pt].pos() if pt in points else None for pt in polygon_id
        ]
        non_none_cnt = len([p for p in polygon if p is not None])
        if non_none_cnt == 0:
            self.rect = QRectF()
            self.bounding_rect = QRectF()
            self.setVisible(False)
            return
        self.setVisible(True)
        # First, check if this is a "simple" cell
        walls = self.walls
        real_polygon = [pid for pid in polygon_id if pid in points]
        #sides = [ walls[real_polygon[i], real_polygon[(i+1)%len(real_polygon)]] for i in range(len(real_polygon)) ]
        sides = [None] * len(polygon)
        self.sides = sides
        real_scale_x = self.scale[0] / self.glob_scale
        real_scale_y = self.scale[1] / self.glob_scale
        for i in range(len(polygon)):
            if polygon[i] is not None:  # Find the next
                j = (i + 1) % len(polygon)
                while polygon[j] is None:
                    j = (j + 1) % len(polygon)
                w = [
                    QPointF(p.x() * real_scale_x,
                            p.y() * real_scale_y)
                    for p in walls[polygon_id[i], polygon_id[j]]
                ]
                sides[i] = [polygon[i]] + w + [polygon[j]]
        prev = real_polygon[-1]
        polygon_shape = []
        for i in range(len(polygon)):
            if polygon[i]:
                polygon_shape.append(polygon[i])
                polygon_shape.extend(sides[i])
# Now add the dummy points .. starts at the first non-None point
        if non_none_cnt > 2:
            start = None
            for i in range(len(polygon)):
                if polygon[i] is not None:
                    start = i
                    break
            prev = start
            cur = start + 1 if start + 1 < len(polygon) else 0
            log_debug("Polygon before: [%s]" %
                      ",".join("(%f,%f)" %
                               (p.x(), p.y()) if p is not None else "None"
                               for p in polygon))
            while cur != start:
                if polygon[cur] is None:
                    cnt = 1
                    next = cur + 1 if cur + 1 < len(polygon) else 0
                    while True:
                        if polygon[next] is None:
                            cnt += 1
                        else:
                            break
                        next += 1
                        if next == len(polygon):
                            next = 0
                    #print "%d points missing" % cnt
                    # First, find total length of wall
                    length = 0.0
                    side = sides[prev]
                    for i in range(len(side) - 1):
                        length += dist(side[i], side[i + 1])
                    diff = length / (cnt + 1)  # Distance between two points
                    i = cur
                    p = side[0]
                    for j in range(cnt):
                        l = 0.0
                        found = False
                        for k in range(len(side) - 1):
                            dl = dist(side[k], side[k + 1])
                            l += dl
                            if l > diff * (
                                    1 + 1e-5
                            ):  # Account for accumulation of small errors
                                c = (i + j) % len(polygon)
                                delta = diff - l + dl
                                p = side[k] + (side[k + 1] -
                                               side[k]) * delta / dl
                                s1 = side[:k + 1] + [p]
                                s2 = [p] + side[k + 1:]
                                sides[c - 1] = s1
                                sides[c] = s2
                                side = s2
                                polygon[c] = p
                                found = True
                                break
                        assert found, "Could not find point in polygon for position %d" % (
                            j + i, )
                        #p = p + diff
                        #c = (i+j)%len(polygon)
                        #polygon[c] = QPointF(p)
                    cur = next
                else:
                    prev = cur
                    cur += 1
                if cur >= len(polygon):
                    cur = 0
            assert None not in polygon, "Error, some dummy points were not added"
        else:
            polygon = [p for p in polygon if p is not None]
        center = sum(polygon, QPointF(0, 0)) / float(len(polygon))
        self.center = center
        if len(polygon) > 2:
            polygon = QPolygonF(polygon + [polygon[0]])
            polygon.translate(-center)
            polygon_shape = QPolygonF(polygon_shape + [polygon_shape[0]])
            self.polygon_shape = polygon_shape
            polygon_shape.translate(-center)
            # Translate the sides too
            sides = [[p - center for p in s] for s in sides]
            self.sides = sides
            assert len(sides) == len(polygon) - 1
        elif len(polygon) == 2:
            polygon = QLineF(polygon[0], polygon[1])
            polygon.translate(-center)
        else:
            polygon = None
        self.polygon = polygon
        self.setPos(center)
        params = parameters.instance
        self.prepareGeometryChange()
        size = params.cell_size
        scale = self.scale
        height = size * cos(pi / 6) * scale[1]
        width = size * scale[0]
        pos_x = size * cos(pi / 3) * scale[0]
        self.sel_rect = QRectF(-width, -height, 2 * width, 2 * height)
        if isinstance(polygon, QPolygonF):
            self.rect = self.polygon_shape.boundingRect() | self.sel_rect
        elif isinstance(polygon, QLineF):
            self.rect = QRectF(polygon.p1(),
                               polygon.p2()).normalized() | self.sel_rect
        else:
            self.rect = self.sel_rect
        self.bounding_rect = QRectF(self.rect)
        if self.p1 in points and self.p2 in points:
            self.division_line = QLineF(points[self.p1].pos() - center,
                                        points[self.p2].pos() - center)
        else:
            self.division_line = None
        self.hexagon = QPolygonF([
            QPointF(-width, 0),
            QPointF(-pos_x, height),
            QPointF(pos_x, height),
            QPointF(width, 0),
            QPointF(pos_x, -height),
            QPointF(-pos_x, -height)
        ])
        self.hexagon_path = QPainterPath()
        self.hexagon_path.addPolygon(self.hexagon)
        s1 = QPainterPath()
        if isinstance(self.polygon, QPolygonF):
            s1.addPolygon(polygon_shape)
        elif isinstance(self.polygon, QLineF):
            s1.moveTo(self.polygon.p1())
            s1.lineTo(self.polygon.p2())
        stroke = QPainterPathStroker()
        sel_thick = 3 * params.cell_thickness
        if sel_thick == 0:
            sel_thick = 3
        stroke.setWidth(sel_thick)
        self.stroke = stroke.createStroke(s1)