from PySide6.QtWidgets import QPushButton, QLabel, QVBoxLayout, QWidget from PySide6.QtCore import Qt from PySide6.QtGui import QFont class NavButton(QPushButton): """Bottom navigation button with active underline.""" def __init__(self, text: str): super().__init__() self.setObjectName("NavBtn") self.setCheckable(False) self.setCursor(Qt.PointingHandCursor) self.setMinimumHeight(80) self._wrap = QWidget() wrap_layout = QVBoxLayout(self._wrap) wrap_layout.setContentsMargins(0, 0, 0, 0) wrap_layout.setSpacing(8) self._label = QLabel(text) self._label.setAlignment(Qt.AlignCenter) self._label.setFont(QFont("", 16, 600)) self._underline = QWidget() self._underline.setObjectName("NavUnderline") self._underline.setFixedHeight(4) self._underline.setFixedWidth(44) self._underline.setStyleSheet("background: transparent; border-radius: 2px;") wrap_layout.addStretch(1) wrap_layout.addWidget(self._label) wrap_layout.addWidget(self._underline, 0, Qt.AlignHCenter) wrap_layout.addStretch(1) btn_layout = QVBoxLayout(self) btn_layout.setContentsMargins(0, 0, 0, 0) btn_layout.addWidget(self._wrap) def set_active(self, active: bool): self.setProperty("active", "true" if active else "false") # important to re-polish to apply dynamic property styling: self.style().unpolish(self) self.style().polish(self)