from PySide6.QtWidgets import QPushButton, QLabel, QVBoxLayout, QWidget from PySide6.QtCore import Qt 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._wrap = QWidget() wrap_layout = QVBoxLayout(self._wrap) wrap_layout.setContentsMargins(0, 0, 0, 0) wrap_layout.setSpacing(6) self._label = QLabel(text) self._label.setAlignment(Qt.AlignCenter) self._underline = QWidget() self._underline.setObjectName("NavUnderline") self._underline.setFixedHeight(3) self._underline.setFixedWidth(36) 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)