示例#1
0
class TextAnnotation(Annotation):
    """Text annotation item for the canvas scheme.

    """
    editingFinished = Signal()
    """Emitted when the editing is finished (i.e. the item loses focus)."""

    textEdited = Signal()
    """Emitted when the edited text changes."""
    def __init__(self, parent=None, **kwargs):
        Annotation.__init__(self, parent, **kwargs)
        self.setFlag(QGraphicsItem.ItemIsMovable)
        self.setFlag(QGraphicsItem.ItemIsSelectable)

        self.setFocusPolicy(Qt.ClickFocus)

        self.__textMargins = (2, 2, 2, 2)

        rect = self.geometry().translated(-self.pos())

        ################################
        # PyQt 5.10 crashes because of this call (3)
        #self.__framePathItem = QGraphicsPathItem(self)
        self.__framePathItem = QGraphicsPathItem(None)

        self.__framePathItem.setPen(QPen(Qt.NoPen))

        self.__textItem = GraphicsTextEdit(self)
        self.__textItem.setPlaceholderText(self.tr("Enter text here"))
        self.__textItem.setPos(2, 2)
        self.__textItem.setTextWidth(rect.width() - 4)
        self.__textItem.setTabChangesFocus(True)
        self.__textItem.setTextInteractionFlags(Qt.NoTextInteraction)
        self.__textItem.setFont(self.font())
        self.__textInteractionFlags = Qt.NoTextInteraction

        layout = self.__textItem.document().documentLayout()
        layout.documentSizeChanged.connect(self.__onDocumentSizeChanged)

        self.__updateFrame()

    def adjustSize(self):
        """Resize to a reasonable size.
        """
        self.__textItem.setTextWidth(-1)
        self.__textItem.adjustSize()
        size = self.__textItem.boundingRect().size()
        left, top, right, bottom = self.textMargins()
        geom = QRectF(self.pos(), size + QSizeF(left + right, top + bottom))
        self.setGeometry(geom)

    def setFramePen(self, pen):
        """Set the frame pen. By default Qt.NoPen is used (i.e. the frame
        is not shown).

        """
        self.__framePathItem.setPen(pen)

    def framePen(self):
        """Return the frame pen.
        """
        return self.__framePathItem.pen()

    def setFrameBrush(self, brush):
        """Set the frame brush.
        """
        self.__framePathItem.setBrush(brush)

    def frameBrush(self):
        """Return the frame brush.
        """
        return self.__framePathItem.brush()

    def setPlainText(self, text):
        """Set the annotation plain text.
        """
        self.__textItem.setPlainText(text)

    def toPlainText(self):
        return self.__textItem.toPlainText()

    def setHtml(self, text):
        """Set the annotation rich text.
        """
        self.__textItem.setHtml(text)

    def toHtml(self):
        return self.__textItem.toHtml()

    def setDefaultTextColor(self, color):
        """Set the default text color.
        """
        self.__textItem.setDefaultTextColor(color)

    def defaultTextColor(self):
        return self.__textItem.defaultTextColor()

    def setTextMargins(self, left, top, right, bottom):
        """Set the text margins.
        """
        margins = (left, top, right, bottom)
        if self.__textMargins != margins:
            self.__textMargins = margins
            self.__textItem.setPos(left, top)
            self.__textItem.setTextWidth(
                max(self.geometry().width() - left - right, 0))

    def textMargins(self):
        """Return the text margins.
        """
        return self.__textMargins

    def document(self):
        """Return the QTextDocument instance used internally.
        """
        return self.__textItem.document()

    def setTextCursor(self, cursor):
        self.__textItem.setTextCursor(cursor)

    def textCursor(self):
        return self.__textItem.textCursor()

    def setTextInteractionFlags(self, flags):
        self.__textInteractionFlags = flags

    def textInteractionFlags(self):
        return self.__textInteractionFlags

    def setDefaultStyleSheet(self, stylesheet):
        self.document().setDefaultStyleSheet(stylesheet)

    def mouseDoubleClickEvent(self, event):
        Annotation.mouseDoubleClickEvent(self, event)

        if event.buttons() == Qt.LeftButton and \
                self.__textInteractionFlags & Qt.TextEditable:
            self.startEdit()

    def startEdit(self):
        """Start the annotation text edit process.
        """
        self.__textItem.setTextInteractionFlags(self.__textInteractionFlags)
        self.__textItem.setFocus(Qt.MouseFocusReason)

        # Install event filter to find out when the text item loses focus.
        self.__textItem.installSceneEventFilter(self)
        self.__textItem.document().contentsChanged.connect(self.textEdited)

    def endEdit(self):
        """End the annotation edit.
        """
        self.__textItem.setTextInteractionFlags(Qt.NoTextInteraction)
        self.__textItem.removeSceneEventFilter(self)
        self.__textItem.document().contentsChanged.disconnect(self.textEdited)
        self.editingFinished.emit()

    def __onDocumentSizeChanged(self, size):
        # The size of the text document has changed. Expand the text
        # control rect's height if the text no longer fits inside.
        try:
            rect = self.geometry()
            _, top, _, bottom = self.textMargins()
            if rect.height() < (size.height() + bottom + top):
                rect.setHeight(size.height() + bottom + top)
                self.setGeometry(rect)
        except Exception:
            log.error("error in __onDocumentSizeChanged", exc_info=True)

    def __updateFrame(self):
        rect = self.geometry()
        rect.moveTo(0, 0)
        path = QPainterPath()
        path.addRect(rect)
        self.__framePathItem.setPath(path)

    def resizeEvent(self, event):
        width = event.newSize().width()
        left, _, right, _ = self.textMargins()
        self.__textItem.setTextWidth(max(width - left - right, 0))
        self.__updateFrame()
        QGraphicsWidget.resizeEvent(self, event)

    def sceneEventFilter(self, obj, event):
        if obj is self.__textItem and event.type() == QEvent.FocusOut:
            self.__textItem.focusOutEvent(event)
            self.endEdit()
            return True

        return Annotation.sceneEventFilter(self, obj, event)

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemSelectedHasChanged:
            if self.isSelected():
                self.setFramePen(QPen(Qt.DashDotLine))
            else:
                self.setFramePen(QPen(Qt.NoPen))

        return Annotation.itemChange(self, change, value)

    def changeEvent(self, event):
        if event.type() == QEvent.FontChange:
            self.__textItem.setFont(self.font())

        Annotation.changeEvent(self, event)
示例#2
0
class TableItem(KineticsDisplayItem):
    defaultWidth = 30
    defaultHeight = 30
    defaultPenWidth = 2
    name = constants.ITEM

    def __init__(self, *args, **kwargs):
        KineticsDisplayItem.__init__(self, *args, **kwargs)

        points = [
            QtCore.QPointF(0, TableItem.defaultWidth / 2),
            QtCore.QPointF(TableItem.defaultHeight / 2 - 2, 0),
            QtCore.QPointF(TableItem.defaultWidth / 2 + 2, 0),
            QtCore.QPointF(TableItem.defaultWidth,
                           TableItem.defaultHeight / 2),
        ]

        path = QtGui.QPainterPath()
        path.moveTo(points[0])
        for p in points[1:]:
            path.lineTo(p)
            path.moveTo(p)
        path.moveTo(0, 0)
        path.lineTo(TableItem.defaultWidth, 0)
        path.moveTo(-(TableItem.defaultWidth / 3), TableItem.defaultHeight / 4)
        path.lineTo((TableItem.defaultWidth + 10), TableItem.defaultHeight / 4)

        self.gobj = QGraphicsPathItem(path, self)
        #self.gobj.setToolTip("Need to see what to show unlike conc/nint for pool")
        tabledoc = (moose.element(self.mobj.path)).outputValue
        self.gobj.setToolTip(str(tabledoc))
        self.gobj.setPen(
            QtGui.QPen(QtCore.Qt.black, 2, Qt.Qt.SolidLine, Qt.Qt.RoundCap,
                       Qt.Qt.RoundJoin))
        self.gobj.mobj = self.mobj

    def refresh(self, scale):
        defaultWidth = TableItem.defaultWidth * scale
        defaultHeight = TableItem.defaultHeight * scale
        points = [
            QtCore.QPointF(0, defaultWidth / 2),
            QtCore.QPointF(defaultHeight / 2 - 2, 0),
            QtCore.QPointF(defaultWidth / 2 + 2, 0),
            QtCore.QPointF(defaultWidth, defaultHeight / 2)
        ]
        path = QtGui.QPainterPath()
        path.moveTo(points[0])
        for p in points[1:]:
            path.lineTo(p)
            path.moveTo(p)
        path.moveTo(0, 0)
        path.lineTo(defaultWidth, 0)
        path.moveTo(-(defaultWidth / 3), defaultHeight / 4)
        path.lineTo((defaultWidth + 10), defaultHeight / 4)
        self.gobj.setPath(path)
        TablePen = self.gobj.pen()
        tableWidth = TableItem.defaultPenWidth * scale
        TablePen.setWidth(tableWidth)
        self.gobj.setPen(TablePen)

    def setDisplayProperties(self, x, y, textcolor, bgcolor):
        """Set the display properties of this item."""
        # TODO: check the table bounding reactangle b'cos selection looks ugly
        self.setGeometry(x, y,
                         self.gobj.boundingRect().width(),
                         self.gobj.boundingRect().height())
示例#3
0
class ReacItem(KineticsDisplayItem):
    defaultWidth = 30
    defaultHeight = 30
    defaultPenWidth = 2
    name = constants.ITEM

    def __init__(self, *args, **kwargs):
        KineticsDisplayItem.__init__(self, *args, **kwargs)
        points = [
            QtCore.QPointF(ReacItem.defaultWidth / 4, 0),
            QtCore.QPointF(0, ReacItem.defaultHeight / 4),
            QtCore.QPointF(ReacItem.defaultWidth, ReacItem.defaultHeight / 4),
            QtCore.QPointF(3 * ReacItem.defaultWidth / 4,
                           ReacItem.defaultHeight / 2)
        ]
        path = QtGui.QPainterPath()
        path.moveTo(points[0])
        for p in points[1:]:
            path.lineTo(p)
            path.moveTo(p)
        self.gobj = QGraphicsPathItem(path, self)
        self.gobj.setPen(
            QtGui.QPen(QtCore.Qt.black, 2, Qt.Qt.SolidLine, Qt.Qt.RoundCap,
                       Qt.Qt.RoundJoin))
        self.gobj.mobj = self.mobj
        self._Kf = self.gobj.mobj.Kf
        self._Kb = self.gobj.mobj.Kb
        doc = "Kf\t: " + str(self._Kf) + "\nKb\t: " + str(self._Kb)
        self.gobj.setToolTip(doc)

    def updateValue(self, gobj):
        self._gobj = gobj
        if (isinstance(self._gobj, moose.ReacBase)):
            self._Kf = self._gobj.Kf
            self._Kb = self._gobj.Kb
            doc = "Kf\t: " + str(self._Kf) + "\nKb\t: " + str(self._Kb)
            self.gobj.setToolTip(doc)

    def refresh(self, scale):
        defaultWidth = ReacItem.defaultWidth * scale
        defaultHeight = ReacItem.defaultHeight * scale
        points = [
            QtCore.QPointF(defaultWidth / 4, 0),
            QtCore.QPointF(0, defaultHeight / 4),
            QtCore.QPointF(defaultWidth, defaultHeight / 4),
            QtCore.QPointF(3 * defaultWidth / 4, defaultHeight / 2)
        ]
        path = QtGui.QPainterPath()
        path.moveTo(points[0])
        for p in points[1:]:
            path.lineTo(p)
            path.moveTo(p)

        self.gobj.setPath(path)
        ReacPen = self.gobj.pen()
        defaultpenwidth = ReacItem.defaultPenWidth
        reacWidth = defaultpenwidth * scale
        ReacPen.setWidth(reacWidth)
        self.gobj.setPen(ReacPen)

    def setDisplayProperties(self, x, y, textcolor, bgcolor):
        """Set the display properties of this item."""
        self.setGeometry(x, y,
                         self.gobj.boundingRect().width(),
                         self.gobj.boundingRect().height())
示例#4
0
class MapCanvas(QGraphicsView):

    def __init__(self):
        # UI Init
        super(QGraphicsView, self).__init__()
        self.setAutoFillBackground(True)
        self.setAttribute(Qt.WA_StyledBackground)
        self.setStyleSheet(
            'QGraphicsView { background-color: rgba(0, 0, 0, 255); }'
        )
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setContentsMargins(0, 0, 0, 0)
        self.setTransformationAnchor(self.AnchorViewCenter)
        self.setFocusPolicy(Qt.StrongFocus)
        self.setRenderHint(QPainter.Antialiasing)

        # Class Init
        self._scene = QGraphicsScene(self)
        self.setScene(self._scene)
        self.scale_ratio = 1
        self.map_data = None
        self.map_line_path_items = {}
        self.map_points_items = []
        self.map_points_text_items = []
        self.map_grid_path_item = QGraphicsPathItem()
        self.map_points_player_items = {}
        self.players = {}

        # Application Settings
        self.settings = settings.Settings('parse99')

    def load_map(self, map_name):
        self._scene.clear()
        self.map_data = MapData(map_name)
        self.create_grid_lines()
        self.create_map_lines()
        self.create_map_points()
        self.update_players()
        self.set_scene_padding(self.map_data.map_grid_geometry.width,
                               self.map_data.map_grid_geometry.height)
        self.draw()
        self.centerOn(0, 0)

    def create_grid_lines(self):
        grid_line_width = self.settings.get_value('maps', 'grid_line_width')
        self.map_grid_path_item = QGraphicsPathItem()
        line_path = QPainterPath()
        for map_line in self.map_data.grid_lines:
            line_path.moveTo(map_line.x1, map_line.y1)
            line_path.lineTo(map_line.x2, map_line.y2)
        self.map_grid_path_item = QGraphicsPathItem(line_path)
        color = QColor().fromRgb(255, 255, 255, 25)
        self.map_grid_path_item.setPen(
            QPen(
                color,
                grid_line_width / self.scale_ratio
            )
        )

    def create_map_lines(self):
        map_line_width = self.settings.get_value('maps', 'map_line_width')
        # use color as string for dictionary keys to preserve line colours
        self.map_line_path_items = {}
        line_path = {}
        colors = {}
        for map_line in self.map_data.map_lines:
            key = str(map_line.r) + ',' \
                + str(map_line.g) + ',' \
                + str(map_line.b)
            if key not in line_path.keys():
                line_path[key] = QPainterPath()
                colors[key] = QColor().fromRgb(
                    map_line.r,
                    map_line.g,
                    map_line.b
                )
            line_path[key].moveTo(QPointF(map_line.x1, map_line.y1))
            line_path[key].lineTo(QPointF(map_line.x2, map_line.y2))
        for key in line_path.keys():
            self.map_line_path_items[key] = QGraphicsPathItem(line_path[key])
            self.map_line_path_items[key].setPen(
                QPen(
                    colors[key],
                    map_line_width / self.scale_ratio
                )
            )

    def create_map_points(self):
        self.map_points_text_items = []
        self.map_points_items = []
        for map_point in self.map_data.map_points:
            color = QColor().fromRgb(map_point.r, map_point.g, map_point.b)
            rect = QGraphicsRectItem(
                QRectF(
                    QPointF(map_point.x, map_point.y),
                    QSizeF(5 / self.scale_ratio, 5 / self.scale_ratio)
                )
            )
            rect.setPen(QPen(Qt.black, 1 / self.scale_ratio))
            rect.setBrush(color)
            self.map_points_items.append(rect)
            text = QGraphicsTextItem(map_point.text)
            text.setDefaultTextColor(color)
            text.setPos(map_point.x, map_point.y)
            text.setFont(QFont('Times New Roman', 8 / self.scale_ratio, 2))
            self.map_points_text_items.append(text)

    def draw(self):
        # Draw map grid
        self._scene.addItem(self.map_grid_path_item)

        # Draw map lines
        for key in self.map_line_path_items.keys():
            self._scene.addItem(self.map_line_path_items[key])

        # Draw map points
        for item in self.map_points_items:
            self._scene.addItem(item)

        # Draw map point's text
        for item in self.map_points_text_items:
            self._scene.addItem(item)

    def update_players(self):
        # Convert lists to sets
        player_list_set = set(self.players.keys())

        # Player points and text should be the same so only use one
        player_items_set = set(self.map_points_player_items.keys())

        # calculate size of player circles
        circle_size = max(10, 10 / self.scale_ratio)

        # Draw and/or update all players in players
        for player in player_list_set:
            player_data = self.players[player]
            if player in player_items_set and \
               self.map_points_player_items[player] in self._scene.items():
                # Update
                self.map_points_player_items[player_data.name].setRect(
                    player_data.x - circle_size / 2,
                    player_data.y - circle_size / 2,
                    circle_size,
                    circle_size
                )
            else:
                # Create New Point
                color = QColor().fromRgb(
                    player_data.r,
                    player_data.g,
                    player_data.b
                )
                circle = QGraphicsEllipseItem(
                    player_data.x - circle_size / 2,
                    player_data.y - circle_size / 2,
                    circle_size,
                    circle_size
                )
                circle.setBrush(color)
                self.map_points_player_items[player_data.name] = circle
                self._scene.addItem(
                    self.map_points_player_items[player_data.name]
                )

        # Find/remove players who aren't in players list from the map
        for key in [player for player in player_items_set
                    if player not in player_list_set]:
            self._scene.removeItem(self.map_points_player_items[key])

        # Center map
        self.center()

    def set_scale(self, ratio):
        # Scale scene
        self.setTransform(QTransform())
        self.scale_ratio = ratio
        self.scale(self.scale_ratio, self.scale_ratio)

        # Scale map lines
        map_line_width = self.settings.get_value('maps', 'map_line_width')
        for key in self.map_line_path_items.keys():
            pen = self.map_line_path_items[key].pen()
            pen.setWidth(
                max(
                    map_line_width,
                    map_line_width / self.scale_ratio
                )
            )
            self.map_line_path_items[key].setPen(pen)

        # Scale map grid
        grid_line_width = self.settings.get_value('maps', 'grid_line_width')
        pen = self.map_grid_path_item.pen()
        pen.setWidth(
            max(
                grid_line_width,
                grid_line_width / self.scale_ratio
            )
        )
        self.map_grid_path_item.setPen(pen)

        # Scale map points
        for i, rect in enumerate(self.map_points_items):
            rect.setRect(
                self.map_data.map_points[i].x,
                self.map_data.map_points[i].y,
                max(5, 5 / self.scale_ratio),
                max(5, 5 / self.scale_ratio)
            )

        # Scale map point's text
        for i, text in enumerate(self.map_points_text_items):
            text.setFont(
                QFont(
                    'Times New Roman',
                    max(8, 8 / self.scale_ratio)
                )
            )
            text.setX(
                self.map_data.map_points[i].x + max(5, 5 / self.scale_ratio)
            )

        # Scale player point
        circle_size = max(10, 10 / self.scale_ratio)
        for player in self.map_points_player_items.keys():
            self.map_points_player_items[player].setRect(
                self.players[player].x - circle_size / 2,
                self.players[player].y - circle_size / 2,
                circle_size,
                circle_size
            )

    def set_scene_padding(self, padding_x, padding_y):
        # Make it so that if you are zoomed out, you can still
        # drag the map around (not that smooth)
        rect = self._scene.sceneRect()
        rect.adjust(
            -padding_x * 2, -padding_y * 2, padding_x * 2, padding_y * 2
        )
        self.setSceneRect(rect)

    def draw_loading_screen(self):
        pass

    def fit_to_window(self):
        pass

    def center(self):
        if self.settings.get_value('maps', 'center_on') == 'player':
            # Center on Player for now by default
            # Added try/except because initialization causes resize event
            try:
                if '__you__' in self.players.keys():
                    self.centerOn(
                        self.players['__you__'].x,
                        self.players['__you__'].y
                    )
            except AttributeError as e:
                print("MapCanvas().center():", e)

    def add_player(self, name, time_stamp, location):
        y, x, z = [float(value) for value in location.strip().split(',')]
        y = -y
        x = -x
        if name not in self.players.keys():
            r, g, b = (0, 255, 0)
            flag = '__other__'
            user_level = None
            if name == '__you__':
                r, g, b = (0, 255, 0)
                flag = '__you__'
                user_level = None
            self.players[name] = Player(
                name=name,
                x=x,
                y=y,
                z=z,
                r=r,
                g=g,
                b=b,
                flag=flag,
                user_level=user_level,
                time_stamp=time_stamp
            )
        else:
            self.players[name].x = x
            self.players[name].y = y
            self.players[name].z = z
            self.players[name].time_stamp = time_stamp

    def wheelEvent(self, event):
        # Scale based on scroll wheel direction
        movement = event.angleDelta().y()
        if movement > 0:
            self.set_scale(self.scale_ratio + self.scale_ratio * 0.1)
        else:
            self.set_scale(self.scale_ratio - self.scale_ratio * 0.1)

    def keyPressEvent(self, event):
        # Enable drag mode while control button is being held down
        if event.modifiers() == Qt.ControlModifier:
            self.setDragMode(self.ScrollHandDrag)
        return QGraphicsView.keyPressEvent(self, event)

    def keyReleaseEvent(self, event):
        # Disable drag mode when control button released
        if event.key() == Qt.Key_Control:
            self.setDragMode(self.NoDrag)
        return QGraphicsView.keyPressEvent(self, event)

    def resizeEvent(self, event):
        self.center()
        return QGraphicsView.resizeEvent(self, event)