Beispiel #1
0
 def shape(self):
     path = QPainterPath()
     path.setFillRule(Qt.WindingFill)
     path.addRect(self.rect())
     for handle in self.handles:
         path.addRect(handle.boundingRect())
     return path
Beispiel #2
0
    def __paint_title_background(self, painter: "QPainter"):
        """Paints a little background behind the title text, at the top of the node."""
        title_rect = self.__graphics_title.boundingRect()

        path_title_background = QPainterPath()
        path_title_background.setFillRule(Qt.WindingFill)
        path_title_background.addRoundedRect(
            0,
            0,
            self.background_paint_area().width(),
            title_rect.height(),
            self.round_edge_size,
            self.round_edge_size,
        )

        # (Drawing rects to hide the two botton round edges)
        path_title_background.addRect(
            0,
            title_rect.height() - self.round_edge_size,
            self.round_edge_size,
            self.round_edge_size,
        )

        path_title_background.addRect(
            self.background_paint_area().width() - self.round_edge_size,
            title_rect.height() - self.round_edge_size,
            self.round_edge_size,
            self.round_edge_size,
        )

        painter.setPen(Qt.NoPen)
        painter.setBrush(self.__title_background_brush)
        painter.drawPath(path_title_background.simplified())
    def shape(self):
        """
		Returns the shape of this item as a QPainterPath in local coordinates.
		The shape could be used for many things, like collision detection.

		:return: Returns the shape of this item as a QPainterPath in local coordinates.
		:rtype: QPainterPath
		"""
        path = QPainterPath()
        path.addRect(self.boundingRect())
        return path
Beispiel #4
0
    def paint(self, painter, option, widget):  # pylint: disable=unused-argument
        """
        Draw the minimap outline and viewport box.
        """
        # Minimap outline
        painter.setPen(QPen(Conf.palette_mid, self.PEN_WIDTH))
        path = QPainterPath()
        path.addRect(self._scene_rect)
        painter.drawPath(path)

        # Viewport box
        painter.setPen(
            QPen(Conf.disasm_view_minimap_viewport_color, self.PEN_WIDTH))
        path = QPainterPath()
        path.addRect(self._viewport_rect)
        painter.drawPath(path)
Beispiel #5
0
    def paintPagesView(self):
        # This method paints the page layout, nothing more
        # It also paints the background at page breaks
        # The design is drawn only when the editor is in page mode.
        if (self.m_usePageMode):
            # Draw page breaks
            pageWidth = self.m_pageMetrics.pxPageSize().width()
            pageHeight = self.m_pageMetrics.pxPageSize().height()

            p = QPainter(self.viewport())
            borderPen = QPen(self.palette().dark(), 1)

            curHeight = pageHeight - (self.verticalScrollBar().value() %
                                      pageHeight)

            # Horizontal offset if there is a scroll bar
            horizontalDelta = self.horizontalScrollBar().value()

            # Paint page views while there are remotely more visible pages
            while (curHeight < pageHeight + self.height()):

                p.setRenderHint(QPainter.Antialiasing)
                path = QPainterPath()
                # In painting page, height of the rect is (pageHeight - 10)
                # to give page break
                pageLayout = QRectF(0 - horizontalDelta,
                                    curHeight - pageHeight, pageWidth,
                                    pageHeight - 10)
                path.addRect(pageLayout)
                p.fillPath(path, Qt.white)

                p.setPen(borderPen)
                p.drawPath(path)

                # Go to next page
                curHeight += pageHeight
Beispiel #6
0
 def shape(self):
     """Returns a shape containing the entire bounding rect, to work better with icon transparency."""
     path = QPainterPath()
     path.addRect(self.boundingRect())
     return path
Beispiel #7
0
class QBlock(QCachedGraphicsItem):
    TOP_PADDING = 5
    BOTTOM_PADDING = 5
    LEFT_PADDING = 10
    RIGHT_PADDING = 10
    SPACING = 0

    def __init__(self,
                 workspace,
                 func_addr,
                 disasm_view,
                 disasm,
                 infodock,
                 addr,
                 cfg_nodes,
                 out_branches,
                 parent=None):
        super().__init__(parent=parent)

        # initialization
        self.workspace = workspace
        self.func_addr = func_addr
        self.disasm_view = disasm_view
        self.disasm = disasm
        self.infodock = infodock
        self.variable_manager = infodock.variable_manager
        self.addr = addr
        self.cfg_nodes = cfg_nodes
        self.out_branches = out_branches

        self._config = Conf

        self.objects = []  # instructions and labels
        self._block_item = None  # QPath
        self.addr_to_insns = {}
        self.addr_to_labels = {}

        self._init_widgets()

        self._objects_are_hidden = False

        self._create_block_item()

    #
    # Properties
    #

    @property
    def mode(self):
        raise NotImplementedError

    @property
    def width(self):
        return self.boundingRect().width()

    @property
    def height(self):
        return self.boundingRect().height()

    #
    # Public methods
    #

    def refresh_if_contains_addr(self, addr1, addr2):
        if addr1 in self.addr_to_insns or addr2 in self.addr_to_insns:
            self.refresh()

    def refresh(self):
        for obj in self.objects:
            obj.refresh()
        self.recalculate_size()
        self._create_block_item()
        self.update()

    def size(self):
        return self.width, self.height

    def instruction_position(self, insn_addr):
        if insn_addr in self.addr_to_insns:
            insn = self.addr_to_insns[insn_addr]
            pos = insn.pos()
            return pos.x(), pos.y()

        return None

    #
    # Initialization
    #

    def _create_block_item(self):
        """
        Create the block background and border.
        """

        self._block_item = QPainterPath()
        self._block_item.addRect(0, 0, self.width, self.height)

    def _init_widgets(self):

        self.objects.clear()
        block_objects = get_block_objects(self.disasm, self.cfg_nodes,
                                          self.func_addr)

        for obj in block_objects:
            if isinstance(obj, Instruction):
                out_branch = get_out_branches_for_insn(self.out_branches,
                                                       obj.addr)
                insn = QInstruction(self.workspace,
                                    self.func_addr,
                                    self.disasm_view,
                                    self.disasm,
                                    self.infodock,
                                    obj,
                                    out_branch,
                                    self._config,
                                    parent=self)
                self.objects.append(insn)
                self.addr_to_insns[obj.addr] = insn
            elif isinstance(obj, Label):
                # label
                label = QBlockLabel(obj.addr,
                                    obj.text,
                                    self._config,
                                    self.disasm_view,
                                    self.workspace,
                                    parent=self)
                self.objects.append(label)
                self.addr_to_labels[obj.addr] = label
            elif isinstance(obj, PhiVariable):
                if not isinstance(obj.variable, SimRegisterVariable):
                    phivariable = QPhiVariable(self.workspace,
                                               self.disasm_view,
                                               obj,
                                               self._config,
                                               parent=self)
                    self.objects.append(phivariable)
            elif isinstance(obj, Variables):
                for var in obj.variables:
                    variable = QVariable(self.workspace,
                                         self.disasm_view,
                                         var,
                                         self._config,
                                         parent=self)
                    self.objects.append(variable)
        self.layout_widgets()

    def layout_widgets(self):
        raise NotImplementedError()
Beispiel #8
0
 def shape(self) -> QPainterPath:
     path = QPainterPath()
     path.addRect(14, 14, 82, 82)
     return path
Beispiel #9
0
class QBlock(QCachedGraphicsItem):
    TOP_PADDING = 5
    BOTTOM_PADDING = 5
    LEFT_PADDING = 10
    RIGHT_PADDING = 10
    SPACING = 0

    def __init__(self,
                 workspace,
                 func_addr,
                 disasm_view,
                 disasm,
                 infodock,
                 addr,
                 cfg_nodes,
                 out_branches,
                 scene,
                 parent=None,
                 container=None):
        super().__init__(parent=parent, container=container)
        # initialization
        self.workspace = workspace
        self.func_addr = func_addr
        self.disasm_view = disasm_view
        self.disasm = disasm
        self.infodock = infodock
        self.variable_manager = infodock.variable_manager
        self.addr = addr
        self.cfg_nodes = cfg_nodes
        self.out_branches = out_branches
        self._scene = scene
        self.margins = QMarginsF(self.LEFT_PADDING, self.TOP_PADDING,
                                 self.RIGHT_PADDING, self.BOTTOM_PADDING)

        self._config = Conf

        self.objects = []  # instructions and labels
        self._block_item = None  # type: QPainterPath
        self._block_item_obj = None  # type: QGraphicsPathItem
        self.qblock_annotations = None
        self.addr_to_insns = {}
        self.addr_to_labels = {}

        self._init_widgets()

        self._objects_are_hidden = False

        self._create_block_item()

        self.setAcceptHoverEvents(True)

    #
    # Properties
    #

    @property
    def mode(self):
        raise NotImplementedError

    @property
    def width(self):
        return self.boundingRect().width()

    @property
    def height(self):
        return self.boundingRect().height()

    #
    # Public methods
    #

    def clear_cache(self):
        super().clear_cache()
        for obj in self.objects:
            obj.clear_cache()

    def refresh(self):
        for obj in self.objects:
            obj.refresh()
        self.layout_widgets()
        self.recalculate_size()
        self._create_block_item()
        self.update()

    def reload(self):
        self._init_widgets()
        self.refresh()

    def size(self):
        return self.width, self.height

    def instruction_position(self, insn_addr):
        if insn_addr in self.addr_to_insns:
            insn = self.addr_to_insns[insn_addr]
            pos = insn.pos()
            return pos.x(), pos.y()

        return None

    #
    # Initialization
    #

    def _create_block_item(self):
        """
        Create the block background and border.
        """
        if self._block_item_obj is not None and self._scene is not None:
            self._scene.removeItem(self._block_item_obj)
            self._block_item = None
            self._block_item_obj = None

        self._block_item = QPainterPath()
        self._block_item.addRect(
            self.block_object_group.childrenBoundingRect().marginsAdded(
                self.margins))

    def _init_widgets(self):

        # TODO: hci: refactor: no need for self.objects anymore b/c of self.block_object_group. Using a
        #  QGraphicsItemGroup is a more natural way to group/work with multiple GraphicItems

        if self._scene is not None:
            for obj in self.objects:
                self._scene.removeItem(obj)

        self.objects.clear()
        block_objects = get_block_objects(self.disasm, self.cfg_nodes,
                                          self.func_addr)
        self.block_object_group = QGraphicsItemGroup(parent=self)
        self.block_object_group.setHandlesChildEvents(False)

        for obj in block_objects:
            if isinstance(obj, Instruction):
                out_branch = get_out_branches_for_insn(self.out_branches,
                                                       obj.addr)
                insn = QInstruction(self.workspace,
                                    self.func_addr,
                                    self.disasm_view,
                                    self.disasm,
                                    self.infodock,
                                    obj,
                                    out_branch,
                                    self._config,
                                    parent=self,
                                    container=self._container)
                self.objects.append(insn)
                self.block_object_group.addToGroup(insn)
                self.addr_to_insns[obj.addr] = insn
            elif isinstance(obj, Label):
                # label
                label = QBlockLabel(obj.addr,
                                    obj.text,
                                    self._config,
                                    self.disasm_view,
                                    self.workspace,
                                    self.infodock,
                                    parent=self,
                                    container=self._container)
                self.objects.append(label)
                self.block_object_group.addToGroup(label)
                self.addr_to_labels[obj.addr] = label
            elif isinstance(obj, PhiVariable):
                if not isinstance(obj.variable, SimRegisterVariable):
                    phivariable = QPhiVariable(self.workspace,
                                               self.disasm_view,
                                               obj,
                                               self._config,
                                               parent=self,
                                               container=self._container)
                    self.objects.append(phivariable)
                    self.block_object_group.addToGroup(phivariable)
            elif isinstance(obj, Variables):
                for var in obj.variables:
                    variable = QVariable(self.workspace,
                                         self.disasm_view,
                                         var,
                                         self._config,
                                         parent=self,
                                         container=self._container)
                    self.objects.append(variable)
                    self.block_object_group.addToGroup(variable)
            elif isinstance(obj, FunctionHeader):
                header = QFunctionHeader(self.func_addr,
                                         obj.name,
                                         obj.prototype,
                                         obj.args,
                                         self._config,
                                         self.disasm_view,
                                         self.workspace,
                                         self.infodock,
                                         parent=self,
                                         container=self._container)
                self.objects.append(header)
                self.block_object_group.addToGroup(header)
        self.layout_widgets()

    def layout_widgets(self):
        raise NotImplementedError()
Beispiel #10
0
    def draw_game(self, painter):
        self.my_painters[ModelType.SHIP_MODEL].setup()
        self.my_painters[ModelType.BOLT_MODEL].setup()
        self.my_painters['background'].setup()

        painter.setBrush(QBrush(QColor('#20124d')))
        painter.drawRect(0, 0, self.width(), self.height())
        try:
            # DRAW BACKGROUND
            painter.setPen(QPen(QBrush(QColor(255, 255, 255)), 2,
                                Qt.SolidLine))
            self.my_painters['background'].paint(painter)

            # DRAW DEAD ZONE
            _dz_radius = self.controller.get_dead_zone_radius()
            _xy = self.controller.get_dead_zone_center().tolist()
            _point_center = self.transform_world_to_screen(*_xy, is_point=True)

            # GET MOBILE OBJECTS
            _model_ships = self.controller.get_data_from_players(
                enemy_only=False)
            _model_bolts = self.controller.get_data_from_bolts()
            _model_asteroids = self.controller.get_data_from_asteroids()

            # SET CAMERA PSOTOPM
            _ship_to_follow = None
            if self.camera_is_locked:
                _ship_to_follow = self.controller.get_player(
                    self.controller.get_name())
                if _ship_to_follow is not None and _ship_to_follow.is_alive:
                    self.camera_pst = QPoint(
                        -_ship_to_follow.x + self.width() // 2,
                        _ship_to_follow.y + self.height() // 2)
                elif len(_model_ships):
                    _ship_to_follow = _model_ships[self.camera_increment %
                                                   len(_model_ships)]
                    self.camera_pst = QPoint(
                        -_ship_to_follow.x + self.width() // 2,
                        _ship_to_follow.y + self.height() // 2)

            # DRAW MOBILE OBJECTS
            for _mob in _model_bolts + _model_ships + _model_asteroids:
                self.my_painters[_mob.type].paint(painter, model=_mob)

            # DRAW OVERLAY
            _brush_band = QBrush(QColor('#00284d'))
            _barre_height = 100

            _rect_top_title = QRect(0, 0, self.width(), 50)
            _rect_band = QRect(0, (self.height() - _barre_height) // 2,
                               self.width(), _barre_height)
            _rect_text1 = QRect(0, (self.height() - _barre_height) // 2,
                                self.width(), _barre_height // 2)
            _rect_text2 = QRect(0,
                                self.height() // 2, self.width(),
                                _barre_height // 2)
            _rect_board_score_bg = QRect(self.width() // 2 - 250, 50, 500,
                                         self.height() - 200)
            _rect_board_title = QRect(0, 100, self.width(), 100)
            _rect_board_score = QRect(0, 200, self.width(),
                                      self.height() - 200)
            painter.setPen(QPen(QColor('#ffffff'), 10))
            painter.setFont(QFont('Open Sans', weight=QFont.Bold,
                                  pointSize=20))
            if self.controller.is_party_waiting():
                painter.setPen(QPen(Qt.NoPen))
                painter.setBrush(_brush_band)
                painter.setOpacity(.75)
                painter.drawRect(_rect_band)
                painter.setOpacity(1)
                painter.setPen(QPen(QColor('#ffffff'), 50))
                painter.drawText(_rect_text1, Qt.AlignCenter,
                                 'WAITING FOR PLAYERS')
                painter.drawText(_rect_text2, Qt.AlignCenter,
                                 '{}'.format(self.controller.get_time_left()))
            elif self.controller.is_party_ready_to_fight():
                painter.setPen(QPen(Qt.NoPen))
                painter.setBrush(_brush_band)
                painter.setOpacity(.75)
                painter.drawRect(_rect_band)
                painter.setOpacity(1)
                painter.setPen(
                    QPen(
                        QColor('#ffffff' if self.controller.get_time_left() > 5
                               else '#ff5555'), 50))
                painter.drawText(_rect_text1, Qt.AlignCenter,
                                 'READY TO FIGHT?')
                painter.drawText(_rect_text2, Qt.AlignCenter,
                                 '{}'.format(self.controller.get_time_left()))
            elif self.controller.has_party_winner():
                painter.setPen(QPen(Qt.NoPen))
                painter.setBrush(_brush_band)
                painter.setOpacity(.75)
                painter.drawRect(_rect_board_score_bg)
                painter.setOpacity(1)
                painter.setPen(QPen(QColor('#ffffff'), 50))
                painter.drawText(
                    _rect_board_title, Qt.AlignHCenter,
                    'Winner is: {} !'.format(self.controller.get_winner()))
                _text_score = [
                    '=========================',
                    'PARTY: {}'.format(self.controller.get_party_name()),
                    '========= SCORE ========='
                ]

                painter.setPen(QPen(QColor('#8be9fd'), 50))
                painter.setFont(
                    QFont('Open Sans', weight=QFont.Bold, pointSize=15))
                for _i, _player in enumerate(
                        self.controller.get_rank_board()[::-1]):
                    _text_score.append('> {: >2}. {: >35}'.format(
                        _i + 1, _player))
                painter.drawText(_rect_board_score, Qt.AlignHCenter,
                                 '\n'.join(_text_score))

            elif self.controller.is_party_done():
                painter.drawText(50, 50, 'PARTY DONE !')
            elif self.controller.is_party_in_progress():
                painter.setPen(QPen(Qt.NoPen))
                painter.setBrush(_brush_band)
                painter.setOpacity(.75)
                painter.drawRect(_rect_top_title)
                painter.setOpacity(1)
                painter.setPen(QPen(QColor('#8be9fd'), 50))
                painter.setFont(
                    QFont('Open Sans', weight=QFont.Bold, pointSize=10))
                if _ship_to_follow is not None:
                    painter.drawText(
                        50, 25,
                        'TimeLeft: {1}     |     Alive: {0}    |    Player: {2}    |'
                        '    Life: {3}%'.format(
                            sum([_ship.is_alive for _ship in _model_ships]),
                            self.controller.get_time_left(),
                            _ship_to_follow.name,
                            int(_ship_to_follow.life * 100)))
                else:
                    painter.drawText(
                        50, 25, 'TimeLeft: {1}     |     Alive: {0}'.format(
                            sum([_ship.is_alive for _ship in _model_ships]),
                            self.controller.get_time_left()))
            # DRAW DEAD ZONE FILL
            _path = QPainterPath()
            _path.addRect(
                QRect(_point_center.x() - PartyConst.WIDTH,
                      _point_center.y() - PartyConst.HEIGHT,
                      PartyConst.WIDTH * 2, PartyConst.HEIGHT * 2))
            _path.addEllipse(_point_center, _dz_radius, _dz_radius)
            painter.setPen(QPen(QColor('#00ffff'), 10, Qt.SolidLine))
            painter.setBrush(QBrush(QColor('#00ffff')))
            painter.setOpacity(.25)
            painter.drawPath(_path)
            painter.setOpacity(1.)
            painter.setBrush(QBrush(Qt.NoBrush))
            painter.drawEllipse(_point_center, _dz_radius, _dz_radius)
            painter.setPen(QPen(QColor('#ffffff'), 5, Qt.SolidLine))
            painter.drawEllipse(_point_center, _dz_radius, _dz_radius)

        except Exception as e:
            print('> [ERR] paintEvent: {}:{}'.format(type(e).__name__, e))
Beispiel #11
0
    def getSymbolFromCmnd(self, symbolinfo):
        '''
        Returns the SymbolPath for the symbol described in symbolinfo, 
        which can either be a string or a dictionary.  

        If symbolinfo is a string, it should be the name of a symbol that 
        has already been defined, either as a pre-defined symbol or from 
        a previous symbol definition.

        Current pre-defined symbol names are ones involving circles:
            'dot': very small filled circle
            'dotex': very small filled circle and outer lines of an ex mark
            'dotplus': very small filled circle and outer lines of a plus mark
            'circle': unfilled circle
            'circfill': normal-sized filled circle
            'circex': small unfilled circle and outer lines of an ex mark
            'circplus': small unfilled circle and outer lines of a plus mark

        If symbolinfo is a dictionary, the following key/value pairs are 
        recognized:
            'name' : (string) symbol name (required)
            'pts'  : (sequence of pairs of floats) vertex coordinates
            'fill' : (bool) color-fill symbol?

        If 'pts' is given, the value is coordinates that define the symbol 
        as multiline subpaths in a [-50,50] square for typical size.  The 
        location of the point this symbol represents will be at the center 
        of the square.  A coordinate outside [-100,100] will terminate the 
        current subpath, and the next valid coordinate will start a new subpath. 
        This definition will replace an existing symbol with the given name.

        If 'pts' is not given, the symbol must already be defined, either as 
        a pre-defined symbol (see above) or from a previous symbol definition.

        Raises:
             TypeError  - if symbolinfo is neither a string nor a dictionary
             KeyError   - if symbolinfo is a dictionary and 
                          the key 'name' is not given 
             ValueError - if there are problems generating the symbol
        '''
        # get the information about the symbol
        if isinstance(symbolinfo, str):
            symbol = symbolinfo
            pts = None
            fill = False
        elif isinstance(symbolinfo, dict):
            symbol = symbolinfo['name']
            pts = symbolinfo.get('pts', None)
            fill = symbolinfo.get('fill', False)
        else:
            raise TypeError('symbolinfo must either be a dictionary or a string')

        if pts is None:
            # no path given; check if already defined
            sympath = self.__symbolpaths.get(symbol)
            if sympath is not None:
                return sympath
            # symbol not defined - if well known, create a SymbolPath for it
            if symbol == 'dot':
                path = QPainterPath()
                path.addEllipse(-10.0, -10.0, 20.0, 20.0)
                sympath = SymbolPath(path, True)
            elif symbol == 'dotplus':
                path = QPainterPath()
                path.addEllipse(-10.0, -10.0, 20.0, 20.0)
                # filled path, so need to draw "lines" as rectangles
                path.addRect( -4.0, -50.0,  8.0, 24.0)
                path.addRect( -4.0,  26.0,  8.0, 24.0)
                path.addRect(-50.0,  -4.0, 24.0,  8.0)
                path.addRect( 26.0,  -4.0, 24.0,  8.0)
                sympath = SymbolPath(path, True)
            elif symbol == 'dotex':
                path = QPainterPath()
                path.addEllipse(-10.0, -10.0, 20.0, 20.0)
                # filled path, so need to draw "lines" as rectangles
                path.moveTo(-38.18, -32.53)
                path.lineTo(-32.53, -38.18)
                path.lineTo(-15.56, -21.21)
                path.lineTo(-21.21, -15.56)
                # moveTo adds an implicit closeSubpath in QPainterPath
                path.moveTo(-38.18,  32.53)
                path.lineTo(-32.53,  38.18)
                path.lineTo(-15.56,  21.21)
                path.lineTo(-21.21,  15.56)
                # moveTo adds an implicit closeSubpath in QPainterPath
                path.moveTo( 38.18, -32.53)
                path.lineTo( 32.53, -38.18)
                path.lineTo( 15.56, -21.21)
                path.lineTo( 21.21, -15.56)
                # moveTo adds an implicit closeSubpath in QPainterPath
                path.moveTo( 38.18,  32.53)
                path.lineTo( 32.53,  38.18)
                path.lineTo( 15.56,  21.21)
                path.lineTo( 21.21,  15.56)
                # Qt closes the subpath automatically
                sympath = SymbolPath(path, True)
            elif symbol == 'circle':
                path = QPainterPath()
                path.addEllipse(-35.0, -35.0, 70.0, 70.0)
                sympath = SymbolPath(path, False)
            elif symbol == 'circfill':
                path = QPainterPath()
                path.addEllipse(-39.0, -39.0, 78.0, 78.0)
                sympath = SymbolPath(path, True)
            elif symbol == 'circplus':
                path = QPainterPath()
                path.addEllipse(-20.0, -20.0, 40.0, 40.0)
                # not a filled path, so just draw the lines
                path.moveTo(  0.0, -50.0)
                path.lineTo(  0.0, -20.0)
                path.moveTo(  0.0,  50.0)
                path.lineTo(  0.0,  20.0)
                path.moveTo(-50.0,   0.0)
                path.lineTo(-20.0,   0.0)
                path.moveTo( 50.0,   0.0)
                path.lineTo( 20.0,   0.0)
                sympath = SymbolPath(path, False)
            elif symbol == 'circex':
                path = QPainterPath()
                path.addEllipse(-20.0, -20.0, 40.0, 40.0)
                # not a filled path, so just draw the lines
                path.moveTo(-35.35, -35.35)
                path.lineTo(-14.15, -14.15)
                path.moveTo(-35.35,  35.35)
                path.lineTo(-14.15,  14.15)
                path.moveTo( 35.35, -35.35)
                path.lineTo( 14.15, -14.15)
                path.moveTo( 35.35,  35.35)
                path.lineTo( 14.15,  14.15)
                sympath = SymbolPath(path, False)
            else:
                raise ValueError("Unknown symbol '%s'" % str(symbol))
        else:
            # define (or redefine) a symbol from the given path
            try:
                coords = [ [ float(val) for val in coord ] for coord in pts ]
                if not coords:
                    raise ValueError
                for crd in coords:
                    if len(crd) != 2:
                        raise ValueError
            except Exception:
                raise ValueError('pts, if given, must be a sequence of pairs of numbers')
            path = QPainterPath()
            somethingdrawn = False
            newstart = True
            for (xval, yval) in coords:
                # flip so positive y is up
                yval *= -1.0
                if (xval < -100.0) or (xval > 100.0) or (yval < -100.0) or (yval > 100.0):
                    # end the current subpath
                    newstart = True
                elif newstart:
                    # start a new subpath; moveTo adds an implicit closeSubpath in QPainterPath
                    path.moveTo(xval, yval)
                    newstart = False
                else:
                    # continue the current subpath
                    path.lineTo(xval, yval)
                    somethingdrawn = True
            if not somethingdrawn:
                del path
                raise ValueError('symbol definition does not contain any drawn lines')
            # Qt closes the (sub)path automatically
            sympath = SymbolPath(path, fill)
        # save and return the SymbolPath
        self.__symbolpaths[symbol] = sympath
        return sympath