Source code for editor.widgets.container.sliding_stacked

from PySide6.QtCore import Signal, QAbstractAnimation, QPropertyAnimation, QParallelAnimationGroup, QEasingCurve, QPoint
from PySide6.QtWidgets import QStackedWidget, QGraphicsOpacityEffect

_Auto, _Left2Right, _Right2Left, _Top2Bottom, _Bottom2Top = range(5)

[docs]class SlidingStackedWidget(QStackedWidget):
[docs] animationFinished = Signal()
def __init__(self, parent = None): super().__init__(parent) self.duration = 500 self.animationtype = QEasingCurve.OutQuad self.vertical = False self.wrap = False self.now = 0 self.next = 0 self.pnow = QPoint(0, 0) self.active = False self.enableFade = True self.animgroup = None
[docs] def setFadeEnable(self, enable): self.enableFade = enable
[docs] def setSlidingDuration(self, duration = 500): self.duration = duration
[docs] def setSlidingEase(self, ease): self.animationtype = ease
[docs] def setVerticalSliding(self, vertical = False): self.vertical = vertical
[docs] def slideInNext(self): now = self.currentIndex() if self.wrap or now < self.count() - 1: self.slideInIdx(now + 1) return True else: return False
[docs] def slideInPrev(self): now = self.currentIndex() if self.wrap or now > 0: self.slideInIdx(now - 1) return True else: return False
[docs] def slideInIdx(self, idx, direction = _Auto): count = self.count() if idx > count - 1: direction = self.vertical and _Top2Bottom or _Right2Left idx %= count elif idx < 0: direction = self.vertical and _Bottom2Top or _Left2Right idx %= count self.slideInWgt(self.widget(idx), direction)
[docs] def slideInWgt(self, newWidget, direction = _Auto): if self.active: return self.active = True directionhint = None now = self.currentIndex() next = self.indexOf(newWidget) if now == next: self.active = False return elif now < next: directionhint = self.vertical and _Top2Bottom or _Right2Left else: directionhint = self.vertical and _Bottom2Top or _Left2Right if direction == _Auto: direction = directionhint rect = self.frameRect() offsetx = rect.width() offsety = rect.height() wgtNext = self.widget(next) wgtNow = self.widget(now) wgtNext.setGeometry(0, 0, offsetx, offsety) if direction == _Bottom2Top: offsetx = 0 offsety = -offsety elif direction == _Top2Bottom: offsetx = 0 elif direction == _Right2Left: offsetx = -offsetx offsety = 0 elif direction == _Left2Right: offsety = 0 pnext = wgtNext.pos() pnow = wgtNow.pos() self.pnow = pnow wgtNext.move(pnext.x() - offsetx, pnext.y() - offsety) wgtNext.show() wgtNext.raise_() animnow = QPropertyAnimation(wgtNow, b'pos') animnow.setDuration(self.duration) animnow.setEasingCurve(self.animationtype) animnow.setStartValue(QPoint(pnow.x(), pnow.y())) animnow.setEndValue(QPoint(pnow.x() + offsetx, pnow.y() + offsety)) animnext = QPropertyAnimation(wgtNext, b'pos') animnext.setDuration(self.duration) animnext.setEasingCurve(self.animationtype) animnext.setStartValue(QPoint(pnext.x() - offsetx, pnext.y() - offsety)) animnext.setEndValue(QPoint(pnext.x(), pnext.y())) self.animgroup = QParallelAnimationGroup() self.animgroup.addAnimation(animnow) self.animgroup.addAnimation(animnext) if self.enableFade: animnow_op_eff = QGraphicsOpacityEffect() wgtNow.setGraphicsEffect(animnow_op_eff) animnow_op = QPropertyAnimation(animnow_op_eff, b'opacity') animnow_op.setDuration(self.duration) animnow_op.setStartValue(1) animnow_op.setEndValue(0.2) def animnow_cb(): if animnow_op_eff: animnow_op_eff.deleteLater() animnow_op.finished.connect(animnow_cb) animnext_op_eff = QGraphicsOpacityEffect() animnext_op_eff.setOpacity(0) wgtNext.setGraphicsEffect(animnext_op_eff) animnext_op = QPropertyAnimation(animnext_op_eff, b'opacity') animnext_op.setDuration(self.duration) animnext_op.setStartValue(0.8) animnext_op.setEndValue(1) def animnext_cb(): if animnext_op_eff: animnext_op_eff.deleteLater() animnext_op.finished.connect(animnext_cb) self.animgroup.addAnimation(animnow_op) self.animgroup.addAnimation(animnext_op) self.next = next self.now = now self.active = True self.animgroup.finished.connect(self.onAnimationFinish) self.animgroup.start(QAbstractAnimation.DeleteWhenStopped)
[docs] def onAnimationFinish(self): self.setCurrentIndex(self.next) currwgt = self.widget(self.now) currwgt.hide() currwgt.move(self.pnow) self.active = False self.animationFinished.emit()
if __name__ == '__main__': import sys from PySide6.QtWidgets import QWidget, QPushButton, QApplication
[docs] app = QApplication(sys.argv)
demo = QWidget() demo.resize(500, 400) ssw = SlidingStackedWidget(demo) ssw.setGeometry(50, 50, 400, 200) w1 = QPushButton('Page 1') w2 = QPushButton('Page 2') w3 = QPushButton('Page 3') w1.setStyleSheet("background-color: #6be; border: 0; font-size: 24px; color: white;") w2.setStyleSheet("background-color: #bae; border: 0; font-size: 24px; color: white;") w3.setStyleSheet("background-color: gray; border: 0; font-size: 24px; color: white;") ssw.addWidget(w1) ssw.addWidget(w2) ssw.addWidget(w3) w2.setFixedHeight(100) # ssw.vertical = True ssw.wrap = True btn1 = QPushButton('Prev', demo) btn1.setGeometry(0, 320, 200, 80) btn1.clicked.connect(ssw.slideInPrev) btn2 = QPushButton('Next', demo) btn2.setGeometry(300, 320, 200, 80) btn2.clicked.connect(ssw.slideInNext) demo.show() sys.exit(app.exec())