# coding:utf-8 from typing import Union from PySide6.QtCore import Qt, Signal from PySide6.QtGui import QColor, QIcon, QPainter from PySide6.QtWidgets import QFrame, QHBoxLayout, QLabel, QToolButton, QVBoxLayout, QPushButton from PySide6.QtSvgWidgets import QSvgWidget from ..dialog_box.color_dialog import ColorDialog from ..widgets.combo_box import ComboBox from ..widgets.switch_button import SwitchButton, IndicatorPosition from ..widgets.slider import Slider from ..widgets.icon_widget import IconWidget from ..widgets.button import HyperlinkButton from ...common.style_sheet import FluentStyleSheet from ...common.config import qconfig, isDarkTheme, ConfigItem, OptionsConfigItem from ...common.icon import FluentIconBase class SettingCard(QFrame): """ Setting card """ def __init__(self, icon: Union[str, QIcon, FluentIconBase], title, content=None, parent=None): """ Parameters ---------- icon: str | QIcon | FluentIconBase the icon to be drawn title: str the title of card content: str the content of card parent: QWidget parent widget """ super().__init__(parent=parent) self.iconLabel = IconWidget(icon, self) self.titleLabel = QLabel(title, self) self.contentLabel = QLabel(content or '', self) self.hBoxLayout = QHBoxLayout(self) self.vBoxLayout = QVBoxLayout() if not content: self.contentLabel.hide() self.setFixedHeight(70 if content else 50) self.iconLabel.setFixedSize(16, 16) # initialize layout self.hBoxLayout.setSpacing(0) self.hBoxLayout.setContentsMargins(16, 0, 0, 0) self.hBoxLayout.setAlignment(Qt.AlignVCenter) self.vBoxLayout.setSpacing(0) self.vBoxLayout.setContentsMargins(0, 0, 0, 0) self.vBoxLayout.setAlignment(Qt.AlignVCenter) self.hBoxLayout.addWidget(self.iconLabel, 0, Qt.AlignLeft) self.hBoxLayout.addSpacing(16) self.hBoxLayout.addLayout(self.vBoxLayout) self.vBoxLayout.addWidget(self.titleLabel, 0, Qt.AlignLeft) self.vBoxLayout.addWidget(self.contentLabel, 0, Qt.AlignLeft) self.hBoxLayout.addSpacing(16) self.hBoxLayout.addStretch(1) self.contentLabel.setObjectName('contentLabel') FluentStyleSheet.SETTING_CARD.apply(self) def setTitle(self, title: str): """ set the title of card """ self.titleLabel.setText(title) def setContent(self, content: str): """ set the content of card """ self.contentLabel.setText(content) self.contentLabel.setVisible(bool(content)) def setValue(self, value): """ set the value of config item """ pass class SwitchSettingCard(SettingCard): """ Setting card with switch button """ checkedChanged = Signal(bool) def __init__(self, icon: Union[str, QIcon, FluentIconBase], title, content=None, configItem: ConfigItem = None, parent=None): """ Parameters ---------- icon: str | QIcon | FluentIconBase the icon to be drawn title: str the title of card content: str the content of card configItem: ConfigItem configuration item operated by the card parent: QWidget parent widget """ super().__init__(icon, title, content, parent) self.configItem = configItem self.switchButton = SwitchButton( self.tr('Off'), self, IndicatorPosition.RIGHT) if configItem: self.setValue(qconfig.get(configItem)) configItem.valueChanged.connect(self.setValue) # add switch button to layout self.hBoxLayout.addWidget(self.switchButton, 0, Qt.AlignRight) self.hBoxLayout.addSpacing(16) self.switchButton.checkedChanged.connect(self.__onCheckedChanged) def __onCheckedChanged(self, isChecked: bool): """ switch button checked state changed slot """ self.setValue(isChecked) self.checkedChanged.emit(isChecked) def setValue(self, isChecked: bool): if self.configItem: qconfig.set(self.configItem, isChecked) self.switchButton.setChecked(isChecked) self.switchButton.setText( self.tr('On') if isChecked else self.tr('Off')) def isChecked(self): return self.switchButton.isChecked() class RangeSettingCard(SettingCard): """ Setting card with a slider """ valueChanged = Signal(int) def __init__(self, configItem, icon: Union[str, QIcon, FluentIconBase], title, content=None, parent=None): """ Parameters ---------- configItem: RangeConfigItem configuration item operated by the card icon: str | QIcon | FluentIconBase the icon to be drawn title: str the title of card content: str the content of card parent: QWidget parent widget """ super().__init__(icon, title, content, parent) self.configItem = configItem self.slider = Slider(Qt.Horizontal, self) self.valueLabel = QLabel(self) self.slider.setMinimumWidth(268) self.slider.setSingleStep(1) self.slider.setRange(*configItem.range) self.slider.setValue(configItem.value) self.valueLabel.setNum(configItem.value) self.hBoxLayout.addStretch(1) self.hBoxLayout.addWidget(self.valueLabel, 0, Qt.AlignRight) self.hBoxLayout.addSpacing(6) self.hBoxLayout.addWidget(self.slider, 0, Qt.AlignRight) self.hBoxLayout.addSpacing(16) self.valueLabel.setObjectName('valueLabel') configItem.valueChanged.connect(self.setValue) self.slider.valueChanged.connect(self.__onValueChanged) def __onValueChanged(self, value: int): """ slider value changed slot """ self.setValue(value) self.valueChanged.emit(value) def setValue(self, value): qconfig.set(self.configItem, value) self.valueLabel.setNum(value) self.valueLabel.adjustSize() class PushSettingCard(SettingCard): """ Setting card with a push button """ clicked = Signal() def __init__(self, text, icon: Union[str, QIcon, FluentIconBase], title, content=None, parent=None): """ Parameters ---------- text: str the text of push button icon: str | QIcon | FluentIconBase the icon to be drawn title: str the title of card content: str the content of card parent: QWidget parent widget """ super().__init__(icon, title, content, parent) self.button = QPushButton(text, self) self.hBoxLayout.addWidget(self.button, 0, Qt.AlignRight) self.hBoxLayout.addSpacing(16) self.button.clicked.connect(self.clicked) class PrimaryPushSettingCard(PushSettingCard): """ Push setting card with primary color """ def __init__(self, text, icon, title, content=None, parent=None): super().__init__(text, icon, title, content, parent) self.button.setObjectName('primaryButton') class HyperlinkCard(SettingCard): """ Hyperlink card """ def __init__(self, url, text, icon: Union[str, QIcon, FluentIconBase], title, content=None, parent=None): """ Parameters ---------- url: str the url to be opened text: str text of url icon: str | QIcon | FluentIconBase the icon to be drawn title: str the title of card content: str the content of card text: str the text of push button parent: QWidget parent widget """ super().__init__(icon, title, content, parent) self.linkButton = HyperlinkButton(url, text, self) self.hBoxLayout.addWidget(self.linkButton, 0, Qt.AlignRight) self.hBoxLayout.addSpacing(16) class ColorPickerButton(QToolButton): """ Color picker button """ colorChanged = Signal(QColor) def __init__(self, color: QColor, title: str, parent=None, enableAlpha=False): super().__init__(parent=parent) self.title = title self.enableAlpha = enableAlpha self.setFixedSize(96, 32) self.setAttribute(Qt.WA_TranslucentBackground) self.setColor(color) self.setCursor(Qt.PointingHandCursor) self.clicked.connect(self.__showColorDialog) def __showColorDialog(self): """ show color dialog """ w = ColorDialog(self.color, self.tr( 'Choose ')+self.title, self.window(), self.enableAlpha) w.colorChanged.connect(self.__onColorChanged) w.exec() def __onColorChanged(self, color): """ color changed slot """ self.setColor(color) self.colorChanged.emit(color) def setColor(self, color): """ set color """ self.color = QColor(color) self.update() def paintEvent(self, e): painter = QPainter(self) painter.setRenderHints(QPainter.Antialiasing) pc = QColor(255, 255, 255, 10) if isDarkTheme() else QColor(234, 234, 234) painter.setPen(pc) color = QColor(self.color) if not self.enableAlpha: color.setAlpha(255) painter.setBrush(color) painter.drawRoundedRect(self.rect().adjusted(1, 1, -1, -1), 5, 5) class ColorSettingCard(SettingCard): """ Setting card with color picker """ colorChanged = Signal(QColor) def __init__(self, configItem, icon: Union[str, QIcon, FluentIconBase], title: str, content: str = None, parent=None, enableAlpha=False): """ Parameters ---------- configItem: RangeConfigItem configuration item operated by the card icon: str | QIcon | FluentIconBase the icon to be drawn title: str the title of card content: str the content of card parent: QWidget parent widget enableAlpha: bool whether to enable the alpha channel """ super().__init__(icon, title, content, parent) self.configItem = configItem self.colorPicker = ColorPickerButton( qconfig.get(configItem), title, self, enableAlpha) self.hBoxLayout.addWidget(self.colorPicker, 0, Qt.AlignRight) self.hBoxLayout.addSpacing(16) self.colorPicker.colorChanged.connect(self.__onColorChanged) configItem.valueChanged.connect(self.setValue) def __onColorChanged(self, color: QColor): qconfig.set(self.configItem, color) self.colorChanged.emit(color) def setValue(self, color: QColor): self.colorPicker.setColor(color) qconfig.set(self.configItem, color) class ComboBoxSettingCard(SettingCard): """ Setting card with a combo box """ def __init__(self, configItem: OptionsConfigItem, icon: Union[str, QIcon, FluentIconBase], title, content=None, texts=None, parent=None): """ Parameters ---------- configItem: OptionsConfigItem configuration item operated by the card icon: str | QIcon | FluentIconBase the icon to be drawn title: str the title of card content: str the content of card texts: List[str] the text of items parent: QWidget parent widget """ super().__init__(icon, title, content, parent) self.configItem = configItem self.comboBox = ComboBox(self) self.hBoxLayout.addWidget(self.comboBox, 0, Qt.AlignRight) self.hBoxLayout.addSpacing(16) self.optionToText = {o: t for o, t in zip(configItem.options, texts)} for text, option in zip(texts, configItem.options): self.comboBox.addItem(text, userData=option) self.comboBox.setCurrentText(self.optionToText[qconfig.get(configItem)]) self.comboBox.currentIndexChanged.connect(self._onCurrentIndexChanged) configItem.valueChanged.connect(self.setValue) def _onCurrentIndexChanged(self, index: int): qconfig.set(self.configItem, self.comboBox.itemData(index)) def setValue(self, value): if value not in self.optionToText: return self.comboBox.setCurrentText(self.optionToText[value]) qconfig.set(self.configItem, value)