예제 #1
0
class GameWindow(QGraphicsView):
    def __init__(self, parent=None):
        super(GameWindow, self).__init__(parent=parent)
        self.screen = None
        self.scene = QGraphicsScene()
        self.scene.setSceneRect(
            QRect(left=0,
                  top=0,
                  width=PLAYGROUND_SIZEX * SCALE_FACTORX,
                  height=PLAYGROUND_SIZEY * SCALE_FACTORY))
        self.setFrameStyle(4)
        self.setScene(self.scene)
        self.snake = []
        # define SnakeHead
        self.snake.append(QGraphicsRectItem())
        self.snake[0].setRect(QRect(0, 0, SCALE_FACTORX, SCALE_FACTORY))

        self.snake[0].setBrush(brushHead)
        self.scene.addItem(self.snake[0])
        # define rest of the snake
        for i in range(1, MAX_LENGTH_SNAKE):
            self.snake.append(QGraphicsRectItem())
            self.snake[i].setRect(QRect(0, 0, SCALE_FACTORX, SCALE_FACTORY))
            self.snake[i].setBrush(brushBody)
            self.snake[i].setVisible(False)
            self.scene.addItem(self.snake[i])
        # Create the graphic item for apple
        self.goal = QGraphicsRectItem()
        self.goal.setRect(QRect(0, 0, SCALE_FACTORX, SCALE_FACTORY))
        self.goal.setBrush(brushGoal)
        self.scene.addItem(self.goal)

        self.show()

    def draw(self, state):
        self.goal.setPos(state.goal.x * SCALE_FACTORX,
                         state.goal.y * SCALE_FACTORY)
        self.goal.setVisible(True)
        self.snake[0].setPos(float(state.snake[0].x * SCALE_FACTORX),
                             float(state.snake[0].y * SCALE_FACTORY))
        for i in range(1, state.snake_length):
            self.snake[i].setPos(state.snake[i].x * SCALE_FACTORX,
                                 state.snake[i].y * SCALE_FACTORY)
            self.snake[i].setVisible(True)
        for i in range(state.snake_length, MAX_LENGTH_SNAKE):
            self.snake[i].setVisible(False)

    def screenshot(self):
        self.screen = self.grab()
        self.screen.save("./snake_screen.png")
class NotificationListItem(QGraphicsTextItem):
    def __init__(self):
        """Notification list graphics item.
        Used to show notifications for a ProjectItem
        """
        super().__init__()
        self.bg = QGraphicsRectItem(self.boundingRect(), self)
        bg_brush = QApplication.palette().brush(QPalette.ToolTipBase)
        self.bg.setBrush(bg_brush)
        self.bg.setFlag(QGraphicsItem.ItemStacksBehindParent)
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False)
        self.setZValue(2)

    def setHtml(self, html):
        super().setHtml(html)
        self.adjustSize()
        self.bg.setRect(self.boundingRect())
예제 #3
0
class ObjectLabelItem(QGraphicsTextItem):
    """Provides a label for ObjectItem's."""

    entity_name_edited = Signal(str)

    def __init__(self, entity_item):
        """Initializes item.

        Args:
            entity_item (spinetoolbox.widgets.graph_view_graphics_items.EntityItem): The parent item.
        """
        super().__init__(entity_item)
        self.entity_item = entity_item
        self._font = QApplication.font()
        self._font.setPointSize(11)
        self.setFont(self._font)
        self.bg = QGraphicsRectItem(self)
        self.bg_color = QGuiApplication.palette().color(
            QPalette.Normal, QPalette.ToolTipBase)
        self.bg_color.setAlphaF(0.8)
        self.bg.setBrush(QBrush(self.bg_color))
        self.bg.setPen(Qt.NoPen)
        self.bg.setFlag(QGraphicsItem.ItemStacksBehindParent)
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False)
        self.setAcceptHoverEvents(False)
        self._cursor = self.textCursor()
        self._text_backup = None

    def setPlainText(self, text):
        """Set texts and resets position.

        Args:
            text (str)
        """
        super().setPlainText(text)
        self.reset_position()

    def reset_position(self):
        """Adapts item geometry so text is always centered."""
        rectf = self.boundingRect()
        x = -rectf.width() / 2
        y = rectf.height() + 4
        self.setPos(x, y)
        self.bg.setRect(self.boundingRect())
예제 #4
0
class RankIcon(QGraphicsTextItem):
    def __init__(self, parent):
        """Rank icon graphics item.
        Used to show the rank of a ProjectItem within its DAG

        Args:
            parent (ProjectItemIcon): the parent item
        """
        super().__init__(parent)
        self._parent = parent
        rect_w = parent.rect().width()  # Parent rect width
        self.text_margin = 0.05 * rect_w
        self.bg = QGraphicsRectItem(self.boundingRect(), self)
        bg_brush = QApplication.palette().brush(QPalette.ToolTipBase)
        self.bg.setBrush(bg_brush)
        self.bg.setFlag(QGraphicsItem.ItemStacksBehindParent)
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False)
        font = self.font()
        font.setPointSize(parent.text_font_size)
        font.setBold(True)
        self.setFont(font)
        doc = self.document()
        doc.setDocumentMargin(0)

    def set_rank(self, rank):
        self.setPlainText(str(rank))
        self.adjustSize()
        self.setTextWidth(self.text_margin + self.textWidth())
        self.bg.setRect(self.boundingRect())
        # Align center
        fmt = QTextBlockFormat()
        fmt.setAlignment(Qt.AlignHCenter)
        cursor = self.textCursor()
        cursor.select(QTextCursor.Document)
        cursor.mergeBlockFormat(fmt)
        cursor.clearSelection()
        self.setTextCursor(cursor)
예제 #5
0
class EntityLabelItem(QGraphicsTextItem):
    """Label item for items in GraphViewForm."""

    entity_name_edited = Signal(str)

    def __init__(self, entity_item):
        """Initializes item.

        Args:
            entity_item (spinetoolbox.widgets.graph_view_graphics_items.EntityItem): The parent item.
        """
        super().__init__(entity_item)
        self.entity_item = entity_item
        self._font = QApplication.font()
        self._font.setPointSize(11)
        self.setFont(self._font)
        self.bg = QGraphicsRectItem(self)
        color = QGuiApplication.palette().color(QPalette.Normal,
                                                QPalette.ToolTipBase)
        color.setAlphaF(0.8)
        self.set_bg_color(color)
        self.bg.setFlag(QGraphicsItem.ItemStacksBehindParent)
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False)
        self.setAcceptHoverEvents(False)
        self._cursor = self.textCursor()
        self._text_backup = None

    def setPlainText(self, text):
        """Set texts and resets position.

        Args:
            text (str)
        """
        super().setPlainText(text)
        self.reset_position()

    def reset_position(self):
        """Adapts item geometry so text is always centered."""
        rectf = self.boundingRect()
        x = -rectf.width() / 2
        y = rectf.height() + 4
        self.setPos(x, y)
        self.bg.setRect(self.boundingRect())

    def set_bg_color(self, bg_color):
        """Sets background color.

        Args:
            bg_color (QColor)
        """
        self.bg.setBrush(QBrush(bg_color))

    def start_editing(self):
        """Starts editing."""
        self.setTextInteractionFlags(Qt.TextEditorInteraction)
        self.setFocus()
        cursor = QTextCursor(self._cursor)
        cursor.select(QTextCursor.Document)
        self.setTextCursor(cursor)
        self._text_backup = self.toPlainText()

    def keyPressEvent(self, event):
        """Keeps text centered as the user types.
        Gives up focus when the user presses Enter or Return.

        Args:
            event (QKeyEvent)
        """
        if event.key() in (Qt.Key_Return, Qt.Key_Enter):
            self.clearFocus()
        elif event.key() == Qt.Key_Escape:
            self.setPlainText(self._text_backup)
            self.clearFocus()
        else:
            super().keyPressEvent(event)
        self.reset_position()

    def focusOutEvent(self, event):
        """Ends editing and sends entity_name_edited signal."""
        super().focusOutEvent(event)
        self.setTextInteractionFlags(Qt.NoTextInteraction)
        self.entity_name_edited.emit(self.toPlainText())
        self.setTextCursor(self._cursor)

    def mouseDoubleClickEvent(self, event):
        """Starts editing the name.

        Args:
            event (QGraphicsSceneMouseEvent)
        """
        self.start_editing()
예제 #6
0
class MaskScene(QGraphicsScene):
    _stage_text = 'STAGE %s'

    def __init__(self, main_window, stage=1):
        super().__init__()
        self.main_window = main_window
        self.stage = stage
        self.upper_mask = QGraphicsRectItem(0, 0, content_width, 0)
        self.lower_mask = QGraphicsRectItem(0, content_height, content_width, 0)
        self.stage_text_item = QGraphicsTextItem()
        self.mask_height = 0
        self.animation_timer_1 = QTimer()
        self.animation_timer_2 = QTimer()
        self.animation_timer_3 = QTimer()
        self.selected = None
        self.init()

    def init(self):
        mask_brush = QBrush()
        mask_brush.setColor(Qt.gray)
        mask_brush.setStyle(Qt.SolidPattern)
        mask_pen = QPen()
        mask_pen.setColor(Qt.gray)
        self.upper_mask.setBrush(mask_brush)
        self.lower_mask.setBrush(mask_brush)
        self.upper_mask.setPen(mask_pen)
        self.lower_mask.setPen(mask_pen)
        self.addItem(self.upper_mask)
        self.addItem(self.lower_mask)

        font = QFont()
        font.setPointSize(20)
        font.setBold(True)
        self.stage_text_item.setPlainText(self._stage_text % self.stage)
        self.stage_text_item.setFont(font)
        self.stage_text_item.setDefaultTextColor(Qt.black)
        self.stage_text_item.setX(content_width / 2 - int(self.stage_text_item.boundingRect().width() / 2))
        self.stage_text_item.setY(content_height / 2 - int(self.stage_text_item.boundingRect().height() / 2))

        self.animation_timer_1.setInterval(interval)
        self.animation_timer_1.timeout.connect(self.animation_in)

        self.animation_timer_2.setSingleShot(True)
        self.animation_timer_2.timeout.connect(self.animation_hold)
        self.animation_timer_2.setInterval(800)

        self.animation_timer_3.setInterval(interval)
        self.animation_timer_3.timeout.connect(self.animation_out)

    def next_stage(self):
        self.stage += 1
        self.stage_text_item.setPlainText(self._stage_text % self.stage)

    def reset_stage(self):
        self.stage = 0
        self.stage_text_item.setPlainText(self._stage_text % self.stage)

    def animation_in(self):
        self.mask_height += 10
        finished = False
        if self.mask_height > content_height / 2:
            self.mask_height = content_height / 2
            finished = True
        self.upper_mask.setRect(0, 0, content_width, self.mask_height)
        self.lower_mask.setRect(0, content_height - self.mask_height, content_width, self.mask_height)
        if finished:
            self.addItem(self.stage_text_item)
            self.animation_timer_1.stop()
            self.animation_timer_2.start()

    def animation_out(self):
        self.mask_height -= 10
        finished = False
        if self.mask_height < 0:
            self.mask_height = 0
            finished = True
        self.upper_mask.setRect(0, 0, content_width, self.mask_height)
        self.lower_mask.setRect(0, content_height - self.mask_height, content_width, self.mask_height)
        if finished:
            self.animation_timer_3.stop()
            self.main_window.start_game(self.selected)

    def animation_hold(self):
        self.removeItem(self.stage_text_item)
        self.animation_timer_3.start()
        self.main_window.enter_game_scene()

    def start_animation(self, selected: int):
        self.animation_timer_1.start()
        self.selected = selected
예제 #7
0
class MonitorItem(QGraphicsRectItem, QObject):
    z = 0

    def __init__(self, *a, **kw):
        data = kw.pop("data")
        self.name = kw.pop("name")
        self.window = kw.pop("window")
        super().__init__(0, 0, 0, 0)
        self.setAcceptedMouseButtons(Qt.LeftButton)
        self.label = QGraphicsTextItem("", self)
        self.bottom_edge = QGraphicsRectItem(0, 0, 0, 0, self)
        self.bottom_edge.setBrush(QBrush("red", Qt.SolidPattern))
        self.update_visuals(data)

    def update_visuals(self, monitor):
        self.setRect(0, 0, monitor.res_x, monitor.res_y)
        self.setPos(monitor.pos_x, monitor.pos_y)
        if monitor.orientation == "normal":
            self.bottom_edge.setRect(0, monitor.res_y - 50, monitor.res_x, 50)
        elif monitor.orientation == "left":
            self.bottom_edge.setRect(monitor.res_x - 50, 0, 50, monitor.res_y)
        elif monitor.orientation == "inverted":
            self.bottom_edge.setRect(0, 0, monitor.res_x, 50)
        elif monitor.orientation == "right":
            self.bottom_edge.setRect(0, 0, 50, monitor.res_y)
        if monitor.replica_of:
            label_text = f"{self.name} [{','.join(monitor.replica_of)}]"
        else:
            label_text = self.name
        self.label.setPlainText(label_text)
        label_scale = min(
            self.rect().width() / self.label.boundingRect().width(),
            self.rect().height() / self.label.boundingRect().height(),
        )
        self.label.setScale(label_scale)
        if monitor.enabled:
            if monitor.primary:
                color = QColor("#eee8d5")
                color.setAlpha(200)
                self.setBrush(QBrush(color, Qt.SolidPattern))
                self.setZValue(1000)
            else:
                color = QColor("#ffffff")
                color.setAlpha(200)
                self.setBrush(QBrush(color, Qt.SolidPattern))
                self.setZValue(self.z)
                self.z -= 1
            self.show()
        else:
            color = QColor("#f1f1f1")
            color.setAlpha(200)
            self.setBrush(QBrush(color, Qt.SolidPattern))
            self.setZValue(-1000)
            self.hide()

    def mousePressEvent(self, event):
        self.window.pos_label.show()
        self.setCursor(Qt.ClosedHandCursor)
        self.orig_pos = self.pos()
        self.window.ui.screenCombo.setCurrentText(self.name)

    def mouseReleaseEvent(self, event):
        self.setCursor(Qt.OpenHandCursor)
        self.window.pos_label.hide()
        self.window.monitor_moved()

    def mouseMoveEvent(self, event):
        snaps_x, snaps_y = self.window.possible_snaps(self.name)
        view = event.widget().parent()
        click_pos = event.buttonDownScreenPos(Qt.LeftButton)
        current_pos = event.screenPos()
        new_pos = view.mapFromScene(self.orig_pos) + current_pos - click_pos
        new_pos = view.mapToScene(new_pos)
        delta = view.mapToScene(0, 20).y()
        if not event.modifiers() & Qt.AltModifier:
            # Check for snaps
            x = new_pos.x()
            delta_x = min((abs(x - sx), i) for i, sx in enumerate(snaps_x))
            if delta_x[0] < delta:  # snap
                new_pos.setX(int(snaps_x[delta_x[1]]))
            y = new_pos.y()
            delta_y = min((abs(y - sy), i) for i, sy in enumerate(snaps_y))
            if delta_y[0] < delta:  # snap
                new_pos.setY(int(snaps_y[delta_y[1]]))
        self.setPos(new_pos)
        self.window.show_pos(int(self.pos().x()), int(self.pos().y()))
예제 #8
0
class MonitorItem(QGraphicsRectItem, QObject):
    z = 0

    def __init__(self, *a, **kw):
        data = kw.pop("data")
        self.name = kw.pop("name")
        self.window = kw.pop("window")
        super().__init__(0, 0, 0, 0)
        self.setAcceptedMouseButtons(Qt.LeftButton)
        self.label = QGraphicsTextItem("", self)
        self.bottom_edge = QGraphicsRectItem(0, 0, 0, 0, self)
        self.bottom_edge.setBrush(QBrush("red", Qt.SolidPattern))
        self.update_visuals(data)

    def update_visuals(self, data):
        self.setRect(0, 0, data["res_x"], data["res_y"])
        self.setPos(data["pos_x"], data["pos_y"])
        if data["orientation"] == 0:
            self.bottom_edge.setRect(0, data["res_y"] - 50, data["res_x"], 50)
        elif data["orientation"] == 1:
            self.bottom_edge.setRect(data["res_x"] - 50, 0, 50, data["res_y"])
        elif data["orientation"] == 2:
            self.bottom_edge.setRect(0, 0, data["res_x"], 50)
        elif data["orientation"] == 3:
            self.bottom_edge.setRect(0, 0, 50, data["res_y"])
        if data["replica_of"]:
            label_text = f"{self.name} [{','.join(data['replica_of'])}]"
        else:
            label_text = self.name
        self.label.setPlainText(label_text)
        label_scale = min(
            self.rect().width() / self.label.boundingRect().width(),
            self.rect().height() / self.label.boundingRect().height(),
        )
        self.label.setScale(label_scale)
        if data["enabled"]:
            if data["primary"]:
                color = QColor("#eee8d5")
                color.setAlpha(200)
                self.setBrush(QBrush(color, Qt.SolidPattern))
                self.setZValue(1000)
            else:
                color = QColor("#ffffff")
                color.setAlpha(200)
                self.setBrush(QBrush(color, Qt.SolidPattern))
                self.setZValue(self.z)
                self.z -= 1
        else:
            color = QColor("#f1f1f1")
            color.setAlpha(200)
            self.setBrush(QBrush(color, Qt.SolidPattern))
            self.setZValue(-1000)

        if not data["current_mode"]:  # Disconnected or disabled
            self.hide()
        else:
            self.show()

    def mousePressEvent(self, event):
        self.window.pos_label.show()
        self.setCursor(Qt.ClosedHandCursor)
        self.orig_pos = self.pos()
        self.window.ui.screenCombo.setCurrentText(self.name)

    def mouseReleaseEvent(self, event):
        self.setCursor(Qt.OpenHandCursor)
        self.window.monitor_moved()
        self.window.pos_label.hide()

    def mouseMoveEvent(self, event):
        view = event.widget().parent()
        click_pos = event.buttonDownScreenPos(Qt.LeftButton)
        current_pos = event.screenPos()
        self.setPos(
            view.mapToScene(
                view.mapFromScene(self.orig_pos) + current_pos - click_pos))
        self.window.show_pos(int(self.pos().x()), int(self.pos().y()))
예제 #9
0
class CanvasGraphicsView(QtWidgets.QGraphicsView):
    capture_complete = QtCore.Signal()

    def __init__(self, parent=None):
        super().__init__(parent)

        self.image = None
        self.rect_item = None
        self.start_pos = None

    def setup_scene(self, img: Image):
        #if img.mode != "RGB":
        #img = img.convert("RGB")
        self.image = img
        scene = CanvasGraphicsScene()
        self.setScene(scene)

        #scene固有の初期化
        qtimg = ImageQt(self.image)
        pixmap = QPixmap.fromImage(qtimg).copy()
        pixmap_item = QGraphicsPixmapItem(pixmap)
        self.scene().addItem(pixmap_item)
        pixmap_item.setPos(0, 0)
        self.rect_item = QGraphicsRectItem(0, 0, 200, 200)
        self.rect_item.setPen(QPen(QtCore.Qt.blue, 3))
        self.rect_item.hide()
        self.scene().addItem(self.rect_item)
        self.frame_rect_item = QGraphicsRectItem(0, 0, self.image.width - 3,
                                                 self.image.height - 3)
        self.frame_rect_item.setPen(QPen(QtCore.Qt.red, 5))
        self.scene().addItem(self.frame_rect_item)

        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        img = self.image
        self.setSceneRect(0, 0, img.width, img.height)
        self.setFixedSize(img.width, img.height)

        self._dragging = False
        pass

    def mousePressEvent(self, event):
        event.accept()
        if event.button() == QtCore.Qt.MouseButton.RightButton:
            #self._parent_window.accepted()
            self.capture_complete.emit()
            return
        else:
            self._dragging = True
            orig_pos = self.mapFromGlobal(QCursor.pos())
            scene_pos = self.mapToScene(orig_pos)
            #self.rect_item.show()
            self.start_pos = scene_pos

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.capture_complete.emit()

    def mouseMoveEvent(self, event):
        event.accept()
        if self._dragging:
            orig_pos = self.mapFromGlobal(QCursor.pos())
            now_pos = self.mapToScene(orig_pos)

            s_x = self.start_pos.x()
            s_y = self.start_pos.y()
            n_x = now_pos.x()
            n_y = now_pos.y()

            self.rect_item.setRect(s_x, s_y, max(0, n_x - s_x), n_y - s_y)

            self.rect_item.show()

    def mouseReleaseEvent(self, event):
        event.accept()
        orig_pos = self.mapFromGlobal(QCursor.pos())
        now_pos = self.mapToScene(orig_pos)

        s_x = self.start_pos.x()
        s_y = self.start_pos.y()
        n_x = now_pos.x()
        n_y = now_pos.y()
        data = {"rect": (s_x, s_y, n_x, n_y)}
        res = QtWidgets.QMessageBox.information(None, "確認", "この領域を保存しますか?",
                                                QtWidgets.QMessageBox.Yes,
                                                QtWidgets.QMessageBox.No)
        if res == QtWidgets.QMessageBox.Yes:
            import json
            with open(area_data_path, "w", encoding="utf-8") as f:
                json.dump(data, f)
            self.capture_complete.emit()

        self._dragging = False
        self.rect_item.hide()
예제 #10
0
class TextLineItem(QAbstractGraphicsShapeItem):
    """A one-line text item.

    Default origin point is at the left side of the baseline. This can change if setAlignMode is called. TextLineItem
    also supports drawing text background. Its brush can be set using setBackgroundBrush(). Text must not contain
    newline characters.
    """
    def __init__(self, text=None, parent=None):
        super().__init__(parent)

        self._text = text or ""
        self._elided_text = text or ""
        self._elide_mode = Qt.ElideRight
        self._align_mode = Qt.AlignLeft
        self._max_width = None
        self._font = QFont()
        self._bounding_rect = QRectF()
        """Bounding and drawing rectangle. Determined automatically."""

        self.background = QGraphicsRectItem(self)
        self.background.setPen(Qt.NoPen)
        self.background.setFlag(QGraphicsItem.ItemStacksBehindParent)

        self.adjust()

    def setText(self, text: str, /) -> None:
        if '\n' in text:
            raise ValueError("text must not contain newline characters")

        self.prepareGeometryChange()
        self._text = text
        self.adjust()

    def setElideMode(self, mode: int, /) -> None:
        """Elide mode specifies where the ellipsis should be located when the text is elided. Default value is 
        Qt.ElideRight.
        """
        self.prepareGeometryChange()
        self._elide_mode = mode
        self.adjust()

    def setAlignMode(self, mode: int, /) -> None:
        """Align mode specifies text alignment.

        Text alignment changes the origin point x position:  
        - If mode is Qt.AlignLeft, the origin point is on the left of the baseline.
        - If mode is Qt.AlignHCenter, the origin point is in the center of the baseline.
        - If mode is Qt.AlignRight, the origin point is on the right of the baseline.

        Vertical alignment has no meaning for one line of text and should not be set. Default value is Qt.AlignLeft.
        """
        self.prepareGeometryChange()
        self._align_mode = mode
        self.adjust()

    def setMaximumWidth(self, width, /):
        """Set the maximum width the text is allowed to be. `None` represents unlimited width."""
        self.prepareGeometryChange()
        self._max_width = width
        self.adjust()

    def setFont(self, font: QFont, /) -> None:
        self.prepareGeometryChange()
        self._font = font
        self.adjust()

    def setBackgroundBrush(self, brush: QBrush, /):
        self.background.setBrush(brush)

    def text(self) -> str:
        return self._text

    def elidedText(self) -> str:
        return self._elided_text

    def elideMode(self) -> int:
        return self._elide_mode

    def alignMode(self) -> int:
        return self._align_mode

    def maximumWidth(self):
        """Maximum width the text is allowed to be. `None` represents unlimited width."""
        return self._max_width

    def font(self) -> QFont:
        return self._font

    def backgroundBrush(self):
        return self.background.brush()

    def adjust(self):
        """Adjust the item's geometry in response to changes."""
        metrics = QFontMetricsF(self.font())

        # Get bounding rectangle for full text
        self._bounding_rect = metrics.boundingRect(self.text())

        # Constrain by maximum width
        if self.maximumWidth() is not None:
            self._bounding_rect.setWidth(self.maximumWidth())

        # Compute elided text
        self._elided_text = metrics.elidedText(self.text(), self.elideMode(),
                                               self.boundingRect().width())

        # Get bounding rectangle for elided text
        self._bounding_rect = metrics.boundingRect(self.elidedText())
        # It seems that for small characters like "..." the bounding rect returned is too small. Adjust it by a small
        # value.
        metrics_correction = px(1 / 72)
        self._bounding_rect.adjust(-metrics_correction, 0, metrics_correction,
                                   0)

        # Move origin point according to the alignment
        if self.alignMode() & Qt.AlignLeft:
            self._bounding_rect.moveLeft(0)
        elif self.alignMode() & Qt.AlignRight:
            self._bounding_rect.moveRight(0)
        else:
            self._bounding_rect.moveLeft(-self._bounding_rect.width() / 2)

        # Set background rect
        self.background.setRect(self.boundingRect())

    def boundingRect(self) -> QRectF:
        return self._bounding_rect

    def paint(self, painter: QPainter, option, widget=...) -> None:
        painter.setBrush(self.brush())
        painter.setPen(self.pen())
        painter.setFont(self.font())

        painter.drawText(self.boundingRect(), self.alignMode(),
                         self.elidedText())