65 lines
2.3 KiB
Python
65 lines
2.3 KiB
Python
from PyQt6.QtWidgets import QGroupBox, QWidget, QVBoxLayout
|
|
from PyQt6.QtCore import QPropertyAnimation
|
|
|
|
class CollapsibleGroupBox(QGroupBox):
|
|
def __init__(self, title="", parent=None):
|
|
super().__init__(title, parent)
|
|
self.setCheckable(True)
|
|
self.setChecked(True)
|
|
|
|
self.animation = QPropertyAnimation(self, b"maximumHeight")
|
|
self.animation.setDuration(200)
|
|
|
|
# Connect the toggled signal to our animation function
|
|
self.toggled.connect(self._toggle_animation)
|
|
|
|
self._full_height = 0
|
|
|
|
def set_content_layout(self, layout):
|
|
# We need a wrapper widget to hold the layout
|
|
self.content_widget = QWidget()
|
|
self.content_widget.setStyleSheet("background-color: transparent;")
|
|
self.content_widget.setLayout(layout)
|
|
|
|
main_layout = QVBoxLayout()
|
|
main_layout.setContentsMargins(0, 0, 0, 0)
|
|
main_layout.addWidget(self.content_widget)
|
|
self.setLayout(main_layout)
|
|
|
|
def _toggle_animation(self, checked):
|
|
if not hasattr(self, 'content_widget'):
|
|
return
|
|
|
|
if checked:
|
|
# Expand: show content first, then animate
|
|
self.content_widget.setVisible(True)
|
|
target_height = self.sizeHint().height()
|
|
self.animation.stop()
|
|
self.animation.setStartValue(self.height())
|
|
self.animation.setEndValue(target_height)
|
|
self.animation.finished.connect(self._on_expand_finished)
|
|
self.animation.start()
|
|
else:
|
|
# Collapse
|
|
self.animation.stop()
|
|
self.animation.setStartValue(self.height())
|
|
self.animation.setEndValue(32)
|
|
self.animation.finished.connect(self._on_collapse_finished)
|
|
self.animation.start()
|
|
|
|
def _on_expand_finished(self):
|
|
# Remove height constraint so content can grow dynamically
|
|
self.setMaximumHeight(16777215)
|
|
try:
|
|
self.animation.finished.disconnect(self._on_expand_finished)
|
|
except TypeError:
|
|
pass
|
|
|
|
def _on_collapse_finished(self):
|
|
if not self.isChecked():
|
|
self.content_widget.setVisible(False)
|
|
try:
|
|
self.animation.finished.disconnect(self._on_collapse_finished)
|
|
except TypeError:
|
|
pass
|