def __call__(self, image, duration=0.5): ''' Start the animation. You must have called :meth:`initialize` first. :param duration: Animation duration in seconds. ''' if self.running: return self.after_image = QPixmap.fromImage(image) if self.flip_forwards: self.animation.setStartValue(image.width()) self.animation.setEndValue(0) t = self.before_image self.before_image = self.after_image self.after_image = t self.animation.setEasingCurve(QEasingCurve(QEasingCurve.InExpo)) else: self.animation.setStartValue(0) self.animation.setEndValue(image.width()) self.animation.setEasingCurve(QEasingCurve(QEasingCurve.OutExpo)) self.animation.setDuration(duration * 1000) self.animation.start()
def __init__(self, parent=None): super().__init__(parent) # self.setBackgroundRole(QPalette.Base) # self.setAutoFillBackground(True) self._mousePos = QPoint() self.setAcceptDrops(True) self._dragInProgress = False self._updateTimer = QTimer(self) self._updateTimer.setInterval(100) # 10 Hz self._updateTimer.timeout.connect(self.update) self._animationLoop = 0 self._lastFrameTime = 0 self._animationStartTime = 0 self._easingCurve = QEasingCurve(QEasingCurve.OutInCubic)
def __init__(self, vertical, parent=None): QWidget.__init__(self, parent) self._current_pixmap_size = QSize(120, 120) self.vertical = vertical self.animation = QPropertyAnimation(self, b'current_pixmap_size', self) self.animation.setEasingCurve(QEasingCurve(QEasingCurve.OutExpo)) self.animation.setDuration(1000) self.animation.setStartValue(QSize(0, 0)) self.animation.valueChanged.connect(self.value_changed) self.setSizePolicy( QSizePolicy.Expanding if vertical else QSizePolicy.Minimum, QSizePolicy.Expanding) self.default_pixmap = QPixmap(I('default_cover.png')) self.pixmap = self.default_pixmap self.pwidth = self.pheight = None self.data = {} self.do_layout()
class DndWidget(QWidget): ANIMATION_SPEED = (1.0 / 8) ANIMATION_INITIAL_DELAY = 200 # ms filesDropped = pyqtSignal('QVariantList') def __init__(self, parent=None): super().__init__(parent) # self.setBackgroundRole(QPalette.Base) # self.setAutoFillBackground(True) self._mousePos = QPoint() self.setAcceptDrops(True) self._dragInProgress = False self._updateTimer = QTimer(self) self._updateTimer.setInterval(100) # 10 Hz self._updateTimer.timeout.connect(self.update) self._animationLoop = 0 self._lastFrameTime = 0 self._animationStartTime = 0 self._easingCurve = QEasingCurve(QEasingCurve.OutInCubic) @pyqtSlot() def startAnimation(self): self._updateTimer.start() self._animationLoop = 0 self._animationStartTime = QDateTime.currentMSecsSinceEpoch() @pyqtSlot() def stopAnimation(self): self._updateTimer.stop() def dragEnterEvent(self, e: QDragEnterEvent): logger.debug( f"format: {e.mimeData().formats()}, hasImage: {e.mimeData().hasImage()}" ) ignoreAction = False if not e.mimeData().hasUrls(): ignoreAction = True for url in e.mimeData().urls(): if not url.isLocalFile(): ignoreAction = True if ignoreAction: e.setDropAction(Qt.IgnoreAction) e.ignore() else: e.setDropAction(Qt.CopyAction) e.accept() self._dragInProgress = True self.startAnimation() def dragMoveEvent(self, e: QDragMoveEvent): e.setDropAction(Qt.CopyAction) e.accept() if not self.hasFocus(): self.update() self._mousePos = e.pos() self.startAnimation() def dragLeaveEvent(self, e: QDragLeaveEvent): if not self._dragInProgress: super().dragLeaveEvent(e) e.accept() logger.debug("") self.stopAnimation() self._dragInProgress = False self.update() def dropEvent(self, e: QDropEvent): if e.dropAction() != Qt.CopyAction: e.ignore() e.acceptProposedAction() self.stopAnimation() files = [url.toLocalFile() for url in e.mimeData().urls()] self._dragInProgress = False self.update() self.filesDropped.emit(files) def _drawPulses(self, painter: QPainter): curTime = QDateTime.currentMSecsSinceEpoch() if curTime - self._animationStartTime <= DndWidget.ANIMATION_INITIAL_DELAY: return p = self._mousePos s = self.size() MAX_CIRCLE_RADIUS = max(p.x(), s.width() - p.x(), p.y(), s.height() - p.y()) outerRad = float(curTime - self._lastFrameTime) * (self._animationLoop + 1) outerRad *= DndWidget.ANIMATION_SPEED outerRadRatio = float(outerRad) / MAX_CIRCLE_RADIUS outerRad *= self._easingCurve.valueForProgress(outerRadRatio) INNER_RADIUS_DIFF = 20 innerRad = outerRad - INNER_RADIUS_DIFF logger.debug(f"outerRad={outerRad:.2f}, {(outerRadRatio * 100):.2f}%, " f"curTime={curTime}, lastFrameTime={self._lastFrameTime}") painter.setPen(QPen(QBrush(Qt.red), 3)) painter.drawEllipse(p, outerRad, outerRad) if innerRad > 0: painter.setPen(QPen(QBrush(Qt.blue), 3)) painter.drawEllipse(QPoint(p.x(), p.y()), innerRad, innerRad) if outerRad >= MAX_CIRCLE_RADIUS: self._animationLoop = 0 def _drawText(self, painter: QPainter, text: str): widgetRect: QRect = self.geometry() font: QFont = QFontDatabase.systemFont(QFontDatabase.GeneralFont) font.setPointSize(18) painter.setFont(font) textRect: QRect = painter.boundingRect(widgetRect, Qt.AlignCenter, text) # DEBUG: ... # painter.setPen(QPen(QBrush(Qt.black), 1)) # painter.drawRect(textRect) palette: QPalette = QApplication.instance().palette() painter.setPen(QPen(palette.color(QPalette.Active, QPalette.Dark), 1)) textRect.moveTo(widgetRect.width() / 2 - textRect.width() / 2, widgetRect.height() / 2 - textRect.height() / 2) painter.drawText(textRect, Qt.AlignCenter, text) def paintEvent(self, event: QPaintEvent): super().paintEvent(event) painter = QPainter(self) # painter.fillRect(QRect(QPoint(0, 0), self.size()), Qt.yellow) # DEBUG: Remove painter.setRenderHint(QPainter.Antialiasing) # TODO: Show number of files. if self._dragInProgress: self._drawText(painter, self.tr("Drop Movies")) else: self._drawText(painter, self.tr("Drag Movies Here")) return self._drawPulses(painter) self._lastFrameTime = QDateTime.currentMSecsSinceEpoch() self._animationLoop += 1