204 lines
7.0 KiB
Python
204 lines
7.0 KiB
Python
|
|
# coding: utf-8
|
||
|
|
from enum import Enum
|
||
|
|
|
||
|
|
from PySide6.QtCore import Qt
|
||
|
|
from PySide6.QtGui import QPainter, QColor
|
||
|
|
from PySide6.QtWidgets import QCheckBox, QStyle, QStyleOptionButton, QWidget
|
||
|
|
|
||
|
|
from ...common.icon import FluentIconBase, Theme, getIconColor
|
||
|
|
from ...common.style_sheet import FluentStyleSheet, isDarkTheme, ThemeColor, themeColor, setCustomStyleSheet
|
||
|
|
from ...common.overload import singledispatchmethod
|
||
|
|
from ...common.color import fallbackThemeColor, validColor
|
||
|
|
|
||
|
|
|
||
|
|
class CheckBoxIcon(FluentIconBase, Enum):
|
||
|
|
""" CheckBoxIcon """
|
||
|
|
|
||
|
|
ACCEPT = "Accept"
|
||
|
|
PARTIAL_ACCEPT = "PartialAccept"
|
||
|
|
|
||
|
|
def path(self, theme=Theme.AUTO):
|
||
|
|
c = getIconColor(theme, reverse=True)
|
||
|
|
return f':/qfluentwidgets/images/check_box/{self.value}_{c}.svg'
|
||
|
|
|
||
|
|
|
||
|
|
class CheckBoxState(Enum):
|
||
|
|
""" Check box state """
|
||
|
|
|
||
|
|
NORMAL = 0
|
||
|
|
HOVER = 1
|
||
|
|
PRESSED = 2
|
||
|
|
CHECKED = 3
|
||
|
|
CHECKED_HOVER = 4
|
||
|
|
CHECKED_PRESSED = 5
|
||
|
|
DISABLED = 6
|
||
|
|
CHECKED_DISABLED = 7
|
||
|
|
|
||
|
|
|
||
|
|
class CheckBox(QCheckBox):
|
||
|
|
""" Check box
|
||
|
|
|
||
|
|
Constructors
|
||
|
|
------------
|
||
|
|
* CheckBox(`parent`: QWidget = None)
|
||
|
|
* CheckBox(`text`: str, `parent`: QWidget = None)
|
||
|
|
"""
|
||
|
|
|
||
|
|
@singledispatchmethod
|
||
|
|
def __init__(self, parent: QWidget = None):
|
||
|
|
super().__init__(parent)
|
||
|
|
FluentStyleSheet.CHECK_BOX.apply(self)
|
||
|
|
self.isPressed = False
|
||
|
|
self.isHover = False
|
||
|
|
self.lightCheckedColor = QColor()
|
||
|
|
self.darkCheckedColor = QColor()
|
||
|
|
self.lightTextColor = QColor(0, 0, 0)
|
||
|
|
self.darkTextColor = QColor(255, 255, 255)
|
||
|
|
|
||
|
|
self._states = {}
|
||
|
|
|
||
|
|
@__init__.register
|
||
|
|
def _(self, text: str, parent: QWidget = None):
|
||
|
|
self.__init__(parent)
|
||
|
|
self.setText(text)
|
||
|
|
|
||
|
|
def mousePressEvent(self, e):
|
||
|
|
self.isPressed = True
|
||
|
|
super().mousePressEvent(e)
|
||
|
|
|
||
|
|
def mouseReleaseEvent(self, e):
|
||
|
|
self.isPressed = False
|
||
|
|
super().mouseReleaseEvent(e)
|
||
|
|
|
||
|
|
def enterEvent(self, e):
|
||
|
|
self.isHover = True
|
||
|
|
self.update()
|
||
|
|
|
||
|
|
def leaveEvent(self, e):
|
||
|
|
self.isHover = False
|
||
|
|
self.update()
|
||
|
|
|
||
|
|
def setCheckedColor(self, light, dark):
|
||
|
|
""" set the color of indicator in checked status
|
||
|
|
|
||
|
|
Parameters
|
||
|
|
----------
|
||
|
|
light, dark: str | QColor | Qt.GlobalColor
|
||
|
|
indicator color in light/dark theme mode
|
||
|
|
"""
|
||
|
|
self.lightCheckedColor = QColor(light)
|
||
|
|
self.darkCheckedColor = QColor(dark)
|
||
|
|
self.update()
|
||
|
|
|
||
|
|
def setTextColor(self, light, dark):
|
||
|
|
""" set the color of text
|
||
|
|
|
||
|
|
Parameters
|
||
|
|
----------
|
||
|
|
light, dark: str | QColor | Qt.GlobalColor
|
||
|
|
text color in light/dark theme mode
|
||
|
|
"""
|
||
|
|
self.lightTextColor = QColor(light)
|
||
|
|
self.darkTextColor = QColor(dark)
|
||
|
|
|
||
|
|
setCustomStyleSheet(
|
||
|
|
self,
|
||
|
|
f"CheckBox{{color:{self.lightTextColor.name(QColor.NameFormat.HexArgb)}}}",
|
||
|
|
f"CheckBox{{color:{self.darkTextColor.name(QColor.NameFormat.HexArgb)}}}"
|
||
|
|
)
|
||
|
|
|
||
|
|
def _borderColor(self):
|
||
|
|
if isDarkTheme():
|
||
|
|
map = {
|
||
|
|
CheckBoxState.NORMAL: QColor(255, 255, 255, 141),
|
||
|
|
CheckBoxState.HOVER: QColor(255, 255, 255, 141),
|
||
|
|
CheckBoxState.PRESSED: QColor(255, 255, 255, 40),
|
||
|
|
CheckBoxState.CHECKED : fallbackThemeColor(self.darkCheckedColor),
|
||
|
|
CheckBoxState.CHECKED_HOVER: validColor(self.darkCheckedColor, ThemeColor.DARK_1.color()),
|
||
|
|
CheckBoxState.CHECKED_PRESSED : validColor(self.darkCheckedColor, ThemeColor.DARK_2.color()),
|
||
|
|
CheckBoxState.DISABLED : QColor(255, 255, 255, 41),
|
||
|
|
CheckBoxState.CHECKED_DISABLED : QColor(0, 0, 0, 0)
|
||
|
|
}
|
||
|
|
else:
|
||
|
|
map = {
|
||
|
|
CheckBoxState.NORMAL: QColor(0, 0, 0, 122),
|
||
|
|
CheckBoxState.HOVER: QColor(0, 0, 0, 143),
|
||
|
|
CheckBoxState.PRESSED: QColor(0, 0, 0, 69),
|
||
|
|
CheckBoxState.CHECKED : fallbackThemeColor(self.lightCheckedColor),
|
||
|
|
CheckBoxState.CHECKED_HOVER : validColor(self.lightCheckedColor, ThemeColor.LIGHT_1.color()),
|
||
|
|
CheckBoxState.CHECKED_PRESSED : validColor(self.lightCheckedColor, ThemeColor.LIGHT_2.color()),
|
||
|
|
CheckBoxState.DISABLED : QColor(0, 0, 0, 56),
|
||
|
|
CheckBoxState.CHECKED_DISABLED : QColor(0, 0, 0, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
return map[self._state()]
|
||
|
|
|
||
|
|
def _backgroundColor(self):
|
||
|
|
if isDarkTheme():
|
||
|
|
map = {
|
||
|
|
CheckBoxState.NORMAL: QColor(0, 0, 0, 26),
|
||
|
|
CheckBoxState.HOVER: QColor(255, 255, 255, 11),
|
||
|
|
CheckBoxState.PRESSED: QColor(255, 255, 255, 18),
|
||
|
|
CheckBoxState.CHECKED: fallbackThemeColor(self.darkCheckedColor),
|
||
|
|
CheckBoxState.CHECKED_HOVER: validColor(self.darkCheckedColor, ThemeColor.DARK_1.color()),
|
||
|
|
CheckBoxState.CHECKED_PRESSED: validColor(self.darkCheckedColor, ThemeColor.DARK_2.color()),
|
||
|
|
CheckBoxState.DISABLED: QColor(0, 0, 0, 0),
|
||
|
|
CheckBoxState.CHECKED_DISABLED: QColor(255, 255, 255, 41)
|
||
|
|
}
|
||
|
|
else:
|
||
|
|
map = {
|
||
|
|
CheckBoxState.NORMAL: QColor(0, 0, 0, 6),
|
||
|
|
CheckBoxState.HOVER: QColor(0, 0, 0, 13),
|
||
|
|
CheckBoxState.PRESSED: QColor(0, 0, 0, 31),
|
||
|
|
CheckBoxState.CHECKED: fallbackThemeColor(self.lightCheckedColor),
|
||
|
|
CheckBoxState.CHECKED_HOVER: validColor(self.lightCheckedColor, ThemeColor.LIGHT_1.color()),
|
||
|
|
CheckBoxState.CHECKED_PRESSED: validColor(self.lightCheckedColor, ThemeColor.LIGHT_2.color()),
|
||
|
|
CheckBoxState.DISABLED: QColor(0, 0, 0, 0),
|
||
|
|
CheckBoxState.CHECKED_DISABLED: QColor(0, 0, 0, 56)
|
||
|
|
}
|
||
|
|
|
||
|
|
return map[self._state()]
|
||
|
|
|
||
|
|
def _state(self):
|
||
|
|
if not self.isEnabled():
|
||
|
|
return CheckBoxState.CHECKED_DISABLED if self.isChecked() else CheckBoxState.DISABLED
|
||
|
|
|
||
|
|
if self.isChecked():
|
||
|
|
if self.isPressed:
|
||
|
|
return CheckBoxState.CHECKED_PRESSED
|
||
|
|
if self.isHover:
|
||
|
|
return CheckBoxState.CHECKED_HOVER
|
||
|
|
|
||
|
|
return CheckBoxState.CHECKED
|
||
|
|
else:
|
||
|
|
if self.isPressed:
|
||
|
|
return CheckBoxState.PRESSED
|
||
|
|
if self.isHover:
|
||
|
|
return CheckBoxState.HOVER
|
||
|
|
|
||
|
|
return CheckBoxState.NORMAL
|
||
|
|
|
||
|
|
def paintEvent(self, e):
|
||
|
|
super().paintEvent(e)
|
||
|
|
painter = QPainter(self)
|
||
|
|
painter.setRenderHints(QPainter.RenderHint.Antialiasing)
|
||
|
|
|
||
|
|
# get the rect of indicator
|
||
|
|
opt = QStyleOptionButton()
|
||
|
|
opt.initFrom(self)
|
||
|
|
rect = self.style().subElementRect(QStyle.SE_CheckBoxIndicator, opt, self)
|
||
|
|
|
||
|
|
# draw shape
|
||
|
|
painter.setPen(self._borderColor())
|
||
|
|
painter.setBrush(self._backgroundColor())
|
||
|
|
painter.drawRoundedRect(rect, 4.5, 4.5)
|
||
|
|
|
||
|
|
if not self.isEnabled():
|
||
|
|
painter.setOpacity(0.8)
|
||
|
|
|
||
|
|
# draw icon
|
||
|
|
if self.checkState() == Qt.Checked:
|
||
|
|
CheckBoxIcon.ACCEPT.render(painter, rect)
|
||
|
|
elif self.checkState() == Qt.PartiallyChecked:
|
||
|
|
CheckBoxIcon.PARTIAL_ACCEPT.render(painter, rect)
|