from __future__ import annotations from PySide6.QtCore import Qt from PySide6.QtGui import QColor, QFont, QFontMetrics, QPainter from PySide6.QtWidgets import QWidget class OverlayWidget(QWidget): def __init__(self, parent: QWidget | None = None) -> None: super().__init__(parent) self.setAttribute(Qt.WA_TransparentForMouseEvents) self.setAttribute(Qt.WA_NoSystemBackground) self._visible = True self._metrics: dict[str, float | int | str] = {} def set_visible(self, visible: bool) -> None: self._visible = visible self.update() def set_metrics(self, metrics: dict[str, float | int | str]) -> None: self._metrics = metrics self.update() def paintEvent(self, event) -> None: # noqa: N802 if not self._visible or not self._metrics: return painter = QPainter(self) painter.setRenderHint(QPainter.TextAntialiasing) if "error" in self._metrics: self._paint_error(painter) else: self._paint_metrics(painter) def _paint_metrics(self, painter: QPainter) -> None: lines = [ f"FPS: {self._metrics.get('fps', 0):>7}", f"Frame: {self._metrics.get('frame_time_ms', 0):>7.1f} ms", f"Frames: {self._metrics.get('frame_count', 0):>7}", ] font = QFont("monospace", 11) painter.setFont(font) fm = QFontMetrics(font) text_width = max(fm.horizontalAdvance(line) for line in lines) + 24 text_height = len(lines) * (fm.height() + 6) + 12 painter.fillRect(8, 8, text_width, text_height, QColor(0, 0, 0, 160)) painter.setPen(QColor(0, 255, 0)) for i, line in enumerate(lines): y = 22 + i * (fm.height() + 6) painter.drawText(16, y, line) def _paint_error(self, painter: QPainter) -> None: msg = str(self._metrics.get("error", "Unknown error")) lines = msg.split("\n") font = QFont("monospace", 12) painter.setFont(font) fm = QFontMetrics(font) text_width = max(fm.horizontalAdvance(line) for line in lines) + 24 text_height = len(lines) * (fm.height() + 6) + 12 painter.fillRect(8, 8, text_width, text_height, QColor(0, 0, 0, 200)) painter.setPen(QColor(200, 50, 50)) for i, line in enumerate(lines): y = 22 + i * (fm.height() + 6) painter.drawText(16, y, line)