You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
5.5 KiB
189 lines
5.5 KiB
# coding:utf-8
|
|
from PySide6.QtCore import QEasingCurve, QPropertyAnimation, Qt, QTimer, Signal, QSize, QPoint, QRectF
|
|
from PySide6.QtGui import QPainter
|
|
from PySide6.QtWidgets import QLabel, QWidget, QToolButton, QGraphicsOpacityEffect
|
|
from PySide6.QtSvgWidgets import QSvgWidget
|
|
|
|
from ...common import FluentStyleSheet, isDarkTheme, Theme
|
|
from ...common.icon import FluentIcon as FIF
|
|
|
|
|
|
class StateCloseButton(QToolButton):
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
self.setFixedSize(12, 12)
|
|
self.isPressed = False
|
|
self.isEnter = False
|
|
|
|
def enterEvent(self, e):
|
|
self.isEnter = True
|
|
self.update()
|
|
|
|
def leaveEvent(self, e):
|
|
self.isEnter = False
|
|
self.isPressed = False
|
|
self.update()
|
|
|
|
def mousePressEvent(self, e):
|
|
self.isPressed = True
|
|
self.update()
|
|
super().mousePressEvent(e)
|
|
|
|
def mouseReleaseEvent(self, e):
|
|
self.isPressed = False
|
|
self.update()
|
|
super().mouseReleaseEvent(e)
|
|
|
|
def paintEvent(self, e):
|
|
painter = QPainter(self)
|
|
painter.setRenderHints(QPainter.Antialiasing)
|
|
if self.isPressed:
|
|
painter.setOpacity(0.6)
|
|
elif self.isEnter:
|
|
painter.setOpacity(0.8)
|
|
|
|
theme = Theme.DARK if not isDarkTheme() else Theme.LIGHT
|
|
FIF.CLOSE.render(painter, self.rect(), theme)
|
|
|
|
|
|
class StateToolTip(QWidget):
|
|
""" State tooltip """
|
|
|
|
closedSignal = Signal()
|
|
|
|
def __init__(self, title, content, parent=None):
|
|
"""
|
|
Parameters
|
|
----------
|
|
title: str
|
|
title of tooltip
|
|
|
|
content: str
|
|
content of tooltip
|
|
|
|
parant:
|
|
parent window
|
|
"""
|
|
super().__init__(parent)
|
|
self.title = title
|
|
self.content = content
|
|
|
|
self.titleLabel = QLabel(self.title, self)
|
|
self.contentLabel = QLabel(self.content, self)
|
|
self.rotateTimer = QTimer(self)
|
|
|
|
self.opacityEffect = QGraphicsOpacityEffect(self)
|
|
self.animation = QPropertyAnimation(self.opacityEffect, b"opacity")
|
|
self.closeButton = StateCloseButton(self)
|
|
|
|
self.isDone = False
|
|
self.rotateAngle = 0
|
|
self.deltaAngle = 20
|
|
|
|
self.__initWidget()
|
|
|
|
def __initWidget(self):
|
|
""" initialize widgets """
|
|
self.setAttribute(Qt.WA_StyledBackground)
|
|
self.setGraphicsEffect(self.opacityEffect)
|
|
self.opacityEffect.setOpacity(1)
|
|
self.rotateTimer.setInterval(50)
|
|
self.contentLabel.setMinimumWidth(200)
|
|
|
|
# connect signal to slot
|
|
self.closeButton.clicked.connect(self.__onCloseButtonClicked)
|
|
self.rotateTimer.timeout.connect(self.__rotateTimerFlowSlot)
|
|
|
|
self.__setQss()
|
|
self.__initLayout()
|
|
|
|
self.rotateTimer.start()
|
|
|
|
def __initLayout(self):
|
|
""" initialize layout """
|
|
self.setFixedSize(max(self.titleLabel.width(),
|
|
self.contentLabel.width()) + 56, 51)
|
|
self.titleLabel.move(32, 9)
|
|
self.contentLabel.move(12, 27)
|
|
self.closeButton.move(self.width() - 24, 19)
|
|
|
|
def __setQss(self):
|
|
""" set style sheet """
|
|
self.titleLabel.setObjectName("titleLabel")
|
|
self.contentLabel.setObjectName("contentLabel")
|
|
|
|
FluentStyleSheet.STATE_TOOL_TIP.apply(self)
|
|
|
|
self.titleLabel.adjustSize()
|
|
self.contentLabel.adjustSize()
|
|
|
|
def setTitle(self, title: str):
|
|
""" set the title of tooltip """
|
|
self.title = title
|
|
self.titleLabel.setText(title)
|
|
self.titleLabel.adjustSize()
|
|
|
|
def setContent(self, content: str):
|
|
""" set the content of tooltip """
|
|
self.content = content
|
|
self.contentLabel.setText(content)
|
|
|
|
# adjustSize() will mask spinner get stuck
|
|
self.contentLabel.adjustSize()
|
|
|
|
def setState(self, isDone=False):
|
|
""" set the state of tooltip """
|
|
self.isDone = isDone
|
|
self.update()
|
|
if isDone:
|
|
QTimer.singleShot(1000, self.__fadeOut)
|
|
|
|
def __onCloseButtonClicked(self):
|
|
""" close button clicked slot """
|
|
self.closedSignal.emit()
|
|
self.hide()
|
|
|
|
def __fadeOut(self):
|
|
""" fade out """
|
|
self.rotateTimer.stop()
|
|
self.animation.setDuration(200)
|
|
self.animation.setStartValue(1)
|
|
self.animation.setEndValue(0)
|
|
self.animation.finished.connect(self.deleteLater)
|
|
self.animation.start()
|
|
|
|
def __rotateTimerFlowSlot(self):
|
|
""" rotate timer time out slot """
|
|
self.rotateAngle = (self.rotateAngle + self.deltaAngle) % 360
|
|
self.update()
|
|
|
|
def getSuitablePos(self):
|
|
""" get suitable position in main window """
|
|
for i in range(10):
|
|
dy = i*(self.height() + 16)
|
|
pos = QPoint(self.parent().width() - self.width() - 24, 50+dy)
|
|
widget = self.parent().childAt(pos + QPoint(2, 2))
|
|
if isinstance(widget, StateToolTip):
|
|
pos += QPoint(0, self.height() + 16)
|
|
else:
|
|
break
|
|
|
|
return pos
|
|
|
|
def paintEvent(self, e):
|
|
""" paint state tooltip """
|
|
super().paintEvent(e)
|
|
painter = QPainter(self)
|
|
painter.setRenderHints(QPainter.Antialiasing)
|
|
painter.setPen(Qt.NoPen)
|
|
theme = Theme.DARK if not isDarkTheme() else Theme.LIGHT
|
|
|
|
if not self.isDone:
|
|
painter.translate(19, 18)
|
|
painter.rotate(self.rotateAngle)
|
|
FIF.SYNC.render(painter, QRectF(-8, -8, 16, 16), theme)
|
|
else:
|
|
FIF.COMPLETED.render(painter, QRectF(11, 10, 16, 16), theme)
|
|
|