import logging from PySide6.QtWidgets import ( QGraphicsRectItem, QGraphicsSimpleTextItem, QGraphicsItem ) from PySide6.QtGui import QBrush, QColor, QFont, QFontMetricsF, QPen, Qt from PySide6.QtCore import Signal, QObject, QTimer NORMAL_COLOR = QColor("lightgray") CLICKED_COLOR = QColor("darkgray") TEXT_SCALE_FACTOR = 0.4 CLICK_HIGHLIGHT_DURATION_MS = 100 Z_INDEX_MULTIPLIER = 2.0 class KeyItem(QGraphicsRectItem, QObject): clicked = Signal(str) def __init__(self, label: str): QObject.__init__(self) QGraphicsRectItem.__init__(self) self.logger = logging.getLogger(__name__) self.label = label self.width = 0.0 self.height = 0.0 self.scale_factor = 1.0 self._reset_timer = QTimer() self._reset_timer.setSingleShot(True) self._reset_timer.timeout.connect(self.__reset_color) self.text = QGraphicsSimpleTextItem(label, self) self.text.setFlag(QGraphicsItem.ItemIgnoresTransformations, True) self.__normal_brush = QBrush(NORMAL_COLOR) self.__click_brush = QBrush(CLICKED_COLOR) self.setBrush(self.__normal_brush) def set_geometry(self, x: float, y: float, width: float, height: float): self.width = width self.height = height self.setRect(0, 0, width, height) self.setPos(x, y) self.setTransformOriginPoint(width / 2, height / 2) self.update_label_font() def update_label_font(self): min_dimension = min(self.width, self.height) font_size = min_dimension * TEXT_SCALE_FACTOR font = QFont() font.setPointSizeF(font_size) self.text.setFont(font) metrics = QFontMetricsF(font) text_rect = metrics.boundingRect(self.label) text_x = (self.width - text_rect.width()) / 2 text_y = (self.height - text_rect.height()) / 2 self.text.setPos(text_x, text_y) def set_scale_factor(self, scale: float): scaled_z = scale * Z_INDEX_MULTIPLIER self.scale_factor = scaled_z self.setZValue(scaled_z) self.setScale(scale) def mousePressEvent(self, q_mouse_event): self.logger.info("%s was clicked", self.label) self.clicked.emit(self.label) self.__onclick_color() def __onclick_color(self): self.setBrush(self.__click_brush) self._reset_timer.start(CLICK_HIGHLIGHT_DURATION_MS) def __reset_color(self): self.setBrush(self.__normal_brush)