Python-FastUI-Widgets 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastuiwidgets/__init__.py +12 -0
- fastuiwidgets/_rc/__init__.py +0 -0
- fastuiwidgets/_rc/resource.py +98835 -0
- fastuiwidgets/common/__init__.py +12 -0
- fastuiwidgets/common/animation.py +530 -0
- fastuiwidgets/common/auto_wrap.py +164 -0
- fastuiwidgets/common/color.py +95 -0
- fastuiwidgets/common/config.py +423 -0
- fastuiwidgets/common/exception_handler.py +31 -0
- fastuiwidgets/common/font.py +38 -0
- fastuiwidgets/common/icon.py +703 -0
- fastuiwidgets/common/image_utils.py +198 -0
- fastuiwidgets/common/overload.py +47 -0
- fastuiwidgets/common/router.py +133 -0
- fastuiwidgets/common/screen.py +25 -0
- fastuiwidgets/common/smooth_scroll.py +141 -0
- fastuiwidgets/common/style_sheet.py +512 -0
- fastuiwidgets/common/theme_listener.py +27 -0
- fastuiwidgets/common/translator.py +14 -0
- fastuiwidgets/components/__init__.py +6 -0
- fastuiwidgets/components/date_time/__init__.py +4 -0
- fastuiwidgets/components/date_time/calendar_picker.py +121 -0
- fastuiwidgets/components/date_time/calendar_view.py +671 -0
- fastuiwidgets/components/date_time/date_picker.py +245 -0
- fastuiwidgets/components/date_time/fast_calendar_view.py +487 -0
- fastuiwidgets/components/date_time/picker_base.py +632 -0
- fastuiwidgets/components/date_time/time_picker.py +223 -0
- fastuiwidgets/components/dialog_box/__init__.py +6 -0
- fastuiwidgets/components/dialog_box/color_dialog.py +414 -0
- fastuiwidgets/components/dialog_box/dialog.py +167 -0
- fastuiwidgets/components/dialog_box/folder_list_dialog.py +307 -0
- fastuiwidgets/components/dialog_box/mask_dialog_base.py +120 -0
- fastuiwidgets/components/dialog_box/message_box_base.py +92 -0
- fastuiwidgets/components/dialog_box/message_dialog.py +65 -0
- fastuiwidgets/components/layout/__init__.py +3 -0
- fastuiwidgets/components/layout/expand_layout.py +96 -0
- fastuiwidgets/components/layout/flow_layout.py +236 -0
- fastuiwidgets/components/layout/v_box_layout.py +41 -0
- fastuiwidgets/components/material/__init__.py +6 -0
- fastuiwidgets/components/material/acrylic_combo_box.py +96 -0
- fastuiwidgets/components/material/acrylic_flyout.py +105 -0
- fastuiwidgets/components/material/acrylic_line_edit.py +27 -0
- fastuiwidgets/components/material/acrylic_menu.py +204 -0
- fastuiwidgets/components/material/acrylic_tool_tip.py +39 -0
- fastuiwidgets/components/material/acrylic_widget.py +42 -0
- fastuiwidgets/components/navigation/__init__.py +9 -0
- fastuiwidgets/components/navigation/breadcrumb.py +350 -0
- fastuiwidgets/components/navigation/navigation_bar.py +416 -0
- fastuiwidgets/components/navigation/navigation_interface.py +268 -0
- fastuiwidgets/components/navigation/navigation_panel.py +657 -0
- fastuiwidgets/components/navigation/navigation_widget.py +686 -0
- fastuiwidgets/components/navigation/pivot.py +272 -0
- fastuiwidgets/components/navigation/segmented_widget.py +174 -0
- fastuiwidgets/components/settings/__init__.py +8 -0
- fastuiwidgets/components/settings/custom_color_setting_card.py +139 -0
- fastuiwidgets/components/settings/expand_setting_card.py +390 -0
- fastuiwidgets/components/settings/folder_list_setting_card.py +134 -0
- fastuiwidgets/components/settings/options_setting_card.py +86 -0
- fastuiwidgets/components/settings/setting_card.py +449 -0
- fastuiwidgets/components/settings/setting_card_group.py +48 -0
- fastuiwidgets/components/widgets/__init__.py +41 -0
- fastuiwidgets/components/widgets/acrylic_label.py +261 -0
- fastuiwidgets/components/widgets/button.py +1059 -0
- fastuiwidgets/components/widgets/card_widget.py +369 -0
- fastuiwidgets/components/widgets/check_box.py +203 -0
- fastuiwidgets/components/widgets/combo_box.py +556 -0
- fastuiwidgets/components/widgets/command_bar.py +636 -0
- fastuiwidgets/components/widgets/cycle_list_widget.py +251 -0
- fastuiwidgets/components/widgets/flip_view.py +430 -0
- fastuiwidgets/components/widgets/flyout.py +521 -0
- fastuiwidgets/components/widgets/frameless_window.py +49 -0
- fastuiwidgets/components/widgets/icon_widget.py +53 -0
- fastuiwidgets/components/widgets/info_badge.py +483 -0
- fastuiwidgets/components/widgets/info_bar.py +596 -0
- fastuiwidgets/components/widgets/label.py +553 -0
- fastuiwidgets/components/widgets/line_edit.py +551 -0
- fastuiwidgets/components/widgets/list_view.py +158 -0
- fastuiwidgets/components/widgets/menu.py +1318 -0
- fastuiwidgets/components/widgets/pips_pager.py +331 -0
- fastuiwidgets/components/widgets/progress_bar.py +311 -0
- fastuiwidgets/components/widgets/progress_ring.py +212 -0
- fastuiwidgets/components/widgets/scroll_area.py +125 -0
- fastuiwidgets/components/widgets/scroll_bar.py +673 -0
- fastuiwidgets/components/widgets/separator.py +43 -0
- fastuiwidgets/components/widgets/slider.py +307 -0
- fastuiwidgets/components/widgets/spin_box.py +306 -0
- fastuiwidgets/components/widgets/stacked_widget.py +211 -0
- fastuiwidgets/components/widgets/state_tool_tip.py +188 -0
- fastuiwidgets/components/widgets/switch_button.py +312 -0
- fastuiwidgets/components/widgets/tab_view.py +804 -0
- fastuiwidgets/components/widgets/table_view.py +360 -0
- fastuiwidgets/components/widgets/teaching_tip.py +657 -0
- fastuiwidgets/components/widgets/tool_tip.py +460 -0
- fastuiwidgets/components/widgets/tree_view.py +216 -0
- fastuiwidgets/multimedia/__init__.py +3 -0
- fastuiwidgets/multimedia/media_play_bar.py +319 -0
- fastuiwidgets/multimedia/media_player.py +124 -0
- fastuiwidgets/multimedia/video_widget.py +93 -0
- fastuiwidgets/window/__init__.py +2 -0
- fastuiwidgets/window/fluent_window.py +413 -0
- fastuiwidgets/window/splash_screen.py +92 -0
- fastuiwidgets/window/stacked_widget.py +66 -0
- python_fastui_widgets-1.0.0.dist-info/METADATA +30 -0
- python_fastui_widgets-1.0.0.dist-info/RECORD +107 -0
- python_fastui_widgets-1.0.0.dist-info/WHEEL +5 -0
- python_fastui_widgets-1.0.0.dist-info/licenses/LICENSE +674 -0
- python_fastui_widgets-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,369 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
from typing import List, Union
|
3
|
+
from PySide6.QtCore import Qt, Signal, QRectF, Property, QPropertyAnimation, QPoint, QSize
|
4
|
+
from PySide6.QtGui import QPixmap, QPainter, QColor, QPainterPath, QFont, QIcon
|
5
|
+
from PySide6.QtWidgets import QWidget, QFrame, QVBoxLayout, QHBoxLayout, QLabel
|
6
|
+
|
7
|
+
from ...common.overload import singledispatchmethod
|
8
|
+
from ...common.style_sheet import isDarkTheme, FluentStyleSheet
|
9
|
+
from ...common.animation import BackgroundAnimationWidget, DropShadowAnimation
|
10
|
+
from ...common.font import setFont
|
11
|
+
from ...common.icon import FluentIconBase
|
12
|
+
from .label import BodyLabel, CaptionLabel
|
13
|
+
from .icon_widget import IconWidget
|
14
|
+
|
15
|
+
|
16
|
+
class CardWidget(BackgroundAnimationWidget, QFrame):
|
17
|
+
""" Card widget """
|
18
|
+
|
19
|
+
clicked = Signal()
|
20
|
+
|
21
|
+
def __init__(self, parent=None):
|
22
|
+
super().__init__(parent=parent)
|
23
|
+
self._isClickEnabled = False
|
24
|
+
self._borderRadius = 5
|
25
|
+
|
26
|
+
def mouseReleaseEvent(self, e):
|
27
|
+
super().mouseReleaseEvent(e)
|
28
|
+
self.clicked.emit()
|
29
|
+
|
30
|
+
def setClickEnabled(self, isEnabled: bool):
|
31
|
+
self._isClickEnabled = isEnabled
|
32
|
+
self.update()
|
33
|
+
|
34
|
+
def isClickEnabled(self):
|
35
|
+
return self._isClickEnabled
|
36
|
+
|
37
|
+
def _normalBackgroundColor(self):
|
38
|
+
return QColor(255, 255, 255, 13 if isDarkTheme() else 170)
|
39
|
+
|
40
|
+
def _hoverBackgroundColor(self):
|
41
|
+
return QColor(255, 255, 255, 21 if isDarkTheme() else 64)
|
42
|
+
|
43
|
+
def _pressedBackgroundColor(self):
|
44
|
+
return QColor(255, 255, 255, 8 if isDarkTheme() else 64)
|
45
|
+
|
46
|
+
def getBorderRadius(self):
|
47
|
+
return self._borderRadius
|
48
|
+
|
49
|
+
def setBorderRadius(self, radius: int):
|
50
|
+
self._borderRadius = radius
|
51
|
+
self.update()
|
52
|
+
|
53
|
+
def paintEvent(self, e):
|
54
|
+
painter = QPainter(self)
|
55
|
+
painter.setRenderHints(QPainter.Antialiasing)
|
56
|
+
|
57
|
+
w, h = self.width(), self.height()
|
58
|
+
r = self.borderRadius
|
59
|
+
d = 2 * r
|
60
|
+
|
61
|
+
isDark = isDarkTheme()
|
62
|
+
|
63
|
+
# draw top border
|
64
|
+
path = QPainterPath()
|
65
|
+
# path.moveTo(1, h - r)
|
66
|
+
path.arcMoveTo(1, h - d - 1, d, d, 240)
|
67
|
+
path.arcTo(1, h - d - 1, d, d, 225, -60)
|
68
|
+
path.lineTo(1, r)
|
69
|
+
path.arcTo(1, 1, d, d, -180, -90)
|
70
|
+
path.lineTo(w - r, 1)
|
71
|
+
path.arcTo(w - d - 1, 1, d, d, 90, -90)
|
72
|
+
path.lineTo(w - 1, h - r)
|
73
|
+
path.arcTo(w - d - 1, h - d - 1, d, d, 0, -60)
|
74
|
+
|
75
|
+
topBorderColor = QColor(0, 0, 0, 20)
|
76
|
+
if isDark:
|
77
|
+
if self.isPressed:
|
78
|
+
topBorderColor = QColor(255, 255, 255, 18)
|
79
|
+
elif self.isHover:
|
80
|
+
topBorderColor = QColor(255, 255, 255, 13)
|
81
|
+
else:
|
82
|
+
topBorderColor = QColor(0, 0, 0, 15)
|
83
|
+
|
84
|
+
painter.strokePath(path, topBorderColor)
|
85
|
+
|
86
|
+
# draw bottom border
|
87
|
+
path = QPainterPath()
|
88
|
+
path.arcMoveTo(1, h - d - 1, d, d, 240)
|
89
|
+
path.arcTo(1, h - d - 1, d, d, 240, 30)
|
90
|
+
path.lineTo(w - r - 1, h - 1)
|
91
|
+
path.arcTo(w - d - 1, h - d - 1, d, d, 270, 30)
|
92
|
+
|
93
|
+
bottomBorderColor = topBorderColor
|
94
|
+
if not isDark and self.isHover and not self.isPressed:
|
95
|
+
bottomBorderColor = QColor(0, 0, 0, 27)
|
96
|
+
|
97
|
+
painter.strokePath(path, bottomBorderColor)
|
98
|
+
|
99
|
+
# draw background
|
100
|
+
painter.setPen(Qt.NoPen)
|
101
|
+
rect = self.rect().adjusted(1, 1, -1, -1)
|
102
|
+
painter.setBrush(self.backgroundColor)
|
103
|
+
painter.drawRoundedRect(rect, r, r)
|
104
|
+
|
105
|
+
borderRadius = Property(int, getBorderRadius, setBorderRadius)
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
class SimpleCardWidget(CardWidget):
|
110
|
+
""" Simple card widget """
|
111
|
+
|
112
|
+
def __init__(self, parent=None):
|
113
|
+
super().__init__(parent)
|
114
|
+
|
115
|
+
def _normalBackgroundColor(self):
|
116
|
+
return QColor(255, 255, 255, 13 if isDarkTheme() else 170)
|
117
|
+
|
118
|
+
def _hoverBackgroundColor(self):
|
119
|
+
return self._normalBackgroundColor()
|
120
|
+
|
121
|
+
def _pressedBackgroundColor(self):
|
122
|
+
return self._normalBackgroundColor()
|
123
|
+
|
124
|
+
def paintEvent(self, e):
|
125
|
+
painter = QPainter(self)
|
126
|
+
painter.setRenderHints(QPainter.Antialiasing)
|
127
|
+
painter.setBrush(self.backgroundColor)
|
128
|
+
|
129
|
+
if isDarkTheme():
|
130
|
+
painter.setPen(QColor(0, 0, 0, 48))
|
131
|
+
else:
|
132
|
+
painter.setPen(QColor(0, 0, 0, 12))
|
133
|
+
|
134
|
+
r = self.borderRadius
|
135
|
+
painter.drawRoundedRect(self.rect().adjusted(1, 1, -1, -1), r, r)
|
136
|
+
|
137
|
+
|
138
|
+
|
139
|
+
class ElevatedCardWidget(SimpleCardWidget):
|
140
|
+
""" Card widget with shadow effect """
|
141
|
+
|
142
|
+
def __init__(self, parent=None):
|
143
|
+
super().__init__(parent)
|
144
|
+
self.shadowAni = DropShadowAnimation(self, hoverColor=QColor(0, 0, 0, 20))
|
145
|
+
self.shadowAni.setOffset(0, 5)
|
146
|
+
self.shadowAni.setBlurRadius(38)
|
147
|
+
|
148
|
+
self.elevatedAni = QPropertyAnimation(self, b'pos', self)
|
149
|
+
self.elevatedAni.setDuration(100)
|
150
|
+
|
151
|
+
self._originalPos = self.pos()
|
152
|
+
self.setBorderRadius(8)
|
153
|
+
|
154
|
+
def enterEvent(self, e):
|
155
|
+
super().enterEvent(e)
|
156
|
+
|
157
|
+
if self.elevatedAni.state() != QPropertyAnimation.Running:
|
158
|
+
self._originalPos = self.pos()
|
159
|
+
|
160
|
+
self._startElevateAni(self.pos(), self.pos() - QPoint(0, 3))
|
161
|
+
|
162
|
+
def leaveEvent(self, e):
|
163
|
+
super().leaveEvent(e)
|
164
|
+
self._startElevateAni(self.pos(), self._originalPos)
|
165
|
+
|
166
|
+
def mousePressEvent(self, e):
|
167
|
+
super().mousePressEvent(e)
|
168
|
+
self._startElevateAni(self.pos(), self._originalPos)
|
169
|
+
|
170
|
+
def _startElevateAni(self, start, end):
|
171
|
+
self.elevatedAni.setStartValue(start)
|
172
|
+
self.elevatedAni.setEndValue(end)
|
173
|
+
self.elevatedAni.start()
|
174
|
+
|
175
|
+
def _hoverBackgroundColor(self):
|
176
|
+
return QColor(255, 255, 255, 16) if isDarkTheme() else QColor(255, 255, 255)
|
177
|
+
|
178
|
+
def _pressedBackgroundColor(self):
|
179
|
+
return QColor(255, 255, 255, 6 if isDarkTheme() else 118)
|
180
|
+
|
181
|
+
|
182
|
+
|
183
|
+
class CardSeparator(QWidget):
|
184
|
+
""" Card separator """
|
185
|
+
|
186
|
+
def __init__(self, parent=None):
|
187
|
+
super().__init__(parent=parent)
|
188
|
+
self.setFixedHeight(3)
|
189
|
+
|
190
|
+
def paintEvent(self, e):
|
191
|
+
painter = QPainter(self)
|
192
|
+
painter.setRenderHints(QPainter.Antialiasing)
|
193
|
+
|
194
|
+
if isDarkTheme():
|
195
|
+
painter.setPen(QColor(255, 255, 255, 46))
|
196
|
+
else:
|
197
|
+
painter.setPen(QColor(0, 0, 0, 12))
|
198
|
+
|
199
|
+
painter.drawLine(2, 1, self.width() - 2, 1)
|
200
|
+
|
201
|
+
|
202
|
+
class HeaderCardWidget(SimpleCardWidget):
|
203
|
+
""" Header card widget """
|
204
|
+
|
205
|
+
@singledispatchmethod
|
206
|
+
def __init__(self, parent=None):
|
207
|
+
super().__init__(parent)
|
208
|
+
self.headerView = QWidget(self)
|
209
|
+
self.headerLabel = QLabel(self)
|
210
|
+
self.separator = CardSeparator(self)
|
211
|
+
self.view = QWidget(self)
|
212
|
+
|
213
|
+
self.vBoxLayout = QVBoxLayout(self)
|
214
|
+
self.headerLayout = QHBoxLayout(self.headerView)
|
215
|
+
self.viewLayout = QHBoxLayout(self.view)
|
216
|
+
|
217
|
+
self.headerLayout.addWidget(self.headerLabel)
|
218
|
+
self.headerLayout.setContentsMargins(24, 0, 16, 0)
|
219
|
+
self.headerView.setFixedHeight(48)
|
220
|
+
|
221
|
+
self.vBoxLayout.setSpacing(0)
|
222
|
+
self.vBoxLayout.setContentsMargins(0, 0, 0, 0)
|
223
|
+
self.vBoxLayout.addWidget(self.headerView)
|
224
|
+
self.vBoxLayout.addWidget(self.separator)
|
225
|
+
self.vBoxLayout.addWidget(self.view)
|
226
|
+
|
227
|
+
self.viewLayout.setContentsMargins(24, 24, 24, 24)
|
228
|
+
setFont(self.headerLabel, 15, QFont.DemiBold)
|
229
|
+
|
230
|
+
self.view.setObjectName('view')
|
231
|
+
self.headerView.setObjectName('headerView')
|
232
|
+
self.headerLabel.setObjectName('headerLabel')
|
233
|
+
FluentStyleSheet.CARD_WIDGET.apply(self)
|
234
|
+
|
235
|
+
self._postInit()
|
236
|
+
|
237
|
+
@__init__.register
|
238
|
+
def _(self, title: str, parent=None):
|
239
|
+
self.__init__(parent)
|
240
|
+
self.setTitle(title)
|
241
|
+
|
242
|
+
def getTitle(self):
|
243
|
+
return self.headerLabel.text()
|
244
|
+
|
245
|
+
def setTitle(self, title: str):
|
246
|
+
self.headerLabel.setText(title)
|
247
|
+
|
248
|
+
def _postInit(self):
|
249
|
+
pass
|
250
|
+
|
251
|
+
title = Property(str, getTitle, setTitle)
|
252
|
+
|
253
|
+
|
254
|
+
|
255
|
+
class CardGroupWidget(QWidget):
|
256
|
+
|
257
|
+
def __init__(self, icon: Union[str, FluentIconBase, QIcon], title: str, content: str, parent=None):
|
258
|
+
super().__init__(parent=parent)
|
259
|
+
self.vBoxLayout = QVBoxLayout(self)
|
260
|
+
self.hBoxLayout = QHBoxLayout()
|
261
|
+
|
262
|
+
self.iconWidget = IconWidget(icon)
|
263
|
+
self.titleLabel = BodyLabel(title)
|
264
|
+
self.contentLabel = CaptionLabel(content)
|
265
|
+
self.textLayout = QVBoxLayout()
|
266
|
+
|
267
|
+
self.separator = CardSeparator()
|
268
|
+
|
269
|
+
self.__initWidget()
|
270
|
+
|
271
|
+
def __initWidget(self):
|
272
|
+
self.separator.hide()
|
273
|
+
self.iconWidget.setFixedSize(20, 20)
|
274
|
+
self.contentLabel.setTextColor(QColor(96, 96, 96), QColor(206, 206, 206))
|
275
|
+
|
276
|
+
self.vBoxLayout.setSpacing(0)
|
277
|
+
self.vBoxLayout.setContentsMargins(0, 0, 0, 0)
|
278
|
+
self.vBoxLayout.addLayout(self.hBoxLayout)
|
279
|
+
self.vBoxLayout.addWidget(self.separator)
|
280
|
+
|
281
|
+
self.textLayout.addWidget(self.titleLabel)
|
282
|
+
self.textLayout.addWidget(self.contentLabel)
|
283
|
+
self.hBoxLayout.addWidget(self.iconWidget)
|
284
|
+
self.hBoxLayout.addLayout(self.textLayout)
|
285
|
+
self.hBoxLayout.addStretch(1)
|
286
|
+
|
287
|
+
self.hBoxLayout.setSpacing(15)
|
288
|
+
self.hBoxLayout.setContentsMargins(24, 10, 24, 10)
|
289
|
+
self.textLayout.setContentsMargins(0, 0, 0, 0)
|
290
|
+
self.textLayout.setSpacing(0)
|
291
|
+
self.hBoxLayout.setAlignment(Qt.AlignmentFlag.AlignLeft)
|
292
|
+
self.textLayout.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
293
|
+
|
294
|
+
def title(self):
|
295
|
+
return self.titleLabel.text()
|
296
|
+
|
297
|
+
def setTitle(self, text: str):
|
298
|
+
self.titleLabel.setText(text)
|
299
|
+
|
300
|
+
def content(self):
|
301
|
+
return self.contentLabel.text()
|
302
|
+
|
303
|
+
def setContent(self, text: str):
|
304
|
+
self.contentLabel.setText(text)
|
305
|
+
|
306
|
+
def icon(self):
|
307
|
+
return self.iconWidget.icon
|
308
|
+
|
309
|
+
def setIcon(self, icon: Union[str, FluentIconBase, QIcon]):
|
310
|
+
self.iconWidget.setIcon(icon)
|
311
|
+
|
312
|
+
def setIconSize(self, size: QSize):
|
313
|
+
self.iconWidget.setFixedSize(size)
|
314
|
+
|
315
|
+
def setSeparatorVisible(self, isVisible: bool):
|
316
|
+
self.separator.setVisible(isVisible)
|
317
|
+
|
318
|
+
def isSeparatorVisible(self):
|
319
|
+
return self.separator.isVisible()
|
320
|
+
|
321
|
+
def addWidget(self, widget: QWidget, stretch=0):
|
322
|
+
self.hBoxLayout.addWidget(widget, stretch=stretch)
|
323
|
+
|
324
|
+
|
325
|
+
class GroupHeaderCardWidget(HeaderCardWidget):
|
326
|
+
""" Group header card widget """
|
327
|
+
|
328
|
+
def _postInit(self):
|
329
|
+
super()._postInit()
|
330
|
+
self.groupWidgets = [] # type: List[CardGroupWidget]
|
331
|
+
self.groupLayout = QVBoxLayout()
|
332
|
+
|
333
|
+
self.groupLayout.setSpacing(0)
|
334
|
+
self.viewLayout.setContentsMargins(0, 0, 0, 0)
|
335
|
+
self.groupLayout.setContentsMargins(0, 0, 0, 0)
|
336
|
+
self.viewLayout.addLayout(self.groupLayout)
|
337
|
+
|
338
|
+
def addGroup(self, icon: Union[str, FluentIconBase, QIcon], title: str, content: str, widget: QWidget, stretch=0) -> CardGroupWidget:
|
339
|
+
""" add widget to a new group
|
340
|
+
|
341
|
+
Parameters
|
342
|
+
----------
|
343
|
+
icon: str | QIcon | FluentIconBase
|
344
|
+
the icon to be drawn
|
345
|
+
|
346
|
+
title: str
|
347
|
+
the title of card
|
348
|
+
|
349
|
+
content: str
|
350
|
+
the content of card
|
351
|
+
|
352
|
+
widget: QWidget
|
353
|
+
the widget to be added
|
354
|
+
|
355
|
+
stretch: int
|
356
|
+
the layout stretch of widget
|
357
|
+
"""
|
358
|
+
group = CardGroupWidget(icon, title, content, self)
|
359
|
+
group.addWidget(widget, stretch=stretch)
|
360
|
+
|
361
|
+
if self.groupWidgets:
|
362
|
+
self.groupWidgets[-1].setSeparatorVisible(True)
|
363
|
+
|
364
|
+
self.groupLayout.addWidget(group)
|
365
|
+
self.groupWidgets.append(group)
|
366
|
+
return group
|
367
|
+
|
368
|
+
def groupCount(self):
|
369
|
+
return len(self.groupWidgets)
|
@@ -0,0 +1,203 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
from enum import Enum
|
3
|
+
|
4
|
+
from PySide6.QtCore import Qt
|
5
|
+
from PySide6.QtGui import QPainter, QColor
|
6
|
+
from PySide6.QtWidgets import QCheckBox, QStyle, QStyleOptionButton, QWidget
|
7
|
+
|
8
|
+
from ...common.icon import FluentIconBase, Theme, getIconColor
|
9
|
+
from ...common.style_sheet import FluentStyleSheet, isDarkTheme, ThemeColor, themeColor, setCustomStyleSheet
|
10
|
+
from ...common.overload import singledispatchmethod
|
11
|
+
from ...common.color import fallbackThemeColor, validColor
|
12
|
+
|
13
|
+
|
14
|
+
class CheckBoxIcon(FluentIconBase, Enum):
|
15
|
+
""" CheckBoxIcon """
|
16
|
+
|
17
|
+
ACCEPT = "Accept"
|
18
|
+
PARTIAL_ACCEPT = "PartialAccept"
|
19
|
+
|
20
|
+
def path(self, theme=Theme.AUTO):
|
21
|
+
c = getIconColor(theme, reverse=True)
|
22
|
+
return f':/fastuiwidgets/images/check_box/{self.value}_{c}.svg'
|
23
|
+
|
24
|
+
|
25
|
+
class CheckBoxState(Enum):
|
26
|
+
""" Check box state """
|
27
|
+
|
28
|
+
NORMAL = 0
|
29
|
+
HOVER = 1
|
30
|
+
PRESSED = 2
|
31
|
+
CHECKED = 3
|
32
|
+
CHECKED_HOVER = 4
|
33
|
+
CHECKED_PRESSED = 5
|
34
|
+
DISABLED = 6
|
35
|
+
CHECKED_DISABLED = 7
|
36
|
+
|
37
|
+
|
38
|
+
class CheckBox(QCheckBox):
|
39
|
+
""" Check box
|
40
|
+
|
41
|
+
Constructors
|
42
|
+
------------
|
43
|
+
* CheckBox(`parent`: QWidget = None)
|
44
|
+
* CheckBox(`text`: str, `parent`: QWidget = None)
|
45
|
+
"""
|
46
|
+
|
47
|
+
@singledispatchmethod
|
48
|
+
def __init__(self, parent: QWidget = None):
|
49
|
+
super().__init__(parent)
|
50
|
+
FluentStyleSheet.CHECK_BOX.apply(self)
|
51
|
+
self.isPressed = False
|
52
|
+
self.isHover = False
|
53
|
+
self.lightCheckedColor = QColor()
|
54
|
+
self.darkCheckedColor = QColor()
|
55
|
+
self.lightTextColor = QColor(0, 0, 0)
|
56
|
+
self.darkTextColor = QColor(255, 255, 255)
|
57
|
+
|
58
|
+
self._states = {}
|
59
|
+
|
60
|
+
@__init__.register
|
61
|
+
def _(self, text: str, parent: QWidget = None):
|
62
|
+
self.__init__(parent)
|
63
|
+
self.setText(text)
|
64
|
+
|
65
|
+
def mousePressEvent(self, e):
|
66
|
+
self.isPressed = True
|
67
|
+
super().mousePressEvent(e)
|
68
|
+
|
69
|
+
def mouseReleaseEvent(self, e):
|
70
|
+
self.isPressed = False
|
71
|
+
super().mouseReleaseEvent(e)
|
72
|
+
|
73
|
+
def enterEvent(self, e):
|
74
|
+
self.isHover = True
|
75
|
+
self.update()
|
76
|
+
|
77
|
+
def leaveEvent(self, e):
|
78
|
+
self.isHover = False
|
79
|
+
self.update()
|
80
|
+
|
81
|
+
def setCheckedColor(self, light, dark):
|
82
|
+
""" set the color of indicator in checked status
|
83
|
+
|
84
|
+
Parameters
|
85
|
+
----------
|
86
|
+
light, dark: str | QColor | Qt.GlobalColor
|
87
|
+
indicator color in light/dark theme mode
|
88
|
+
"""
|
89
|
+
self.lightCheckedColor = QColor(light)
|
90
|
+
self.darkCheckedColor = QColor(dark)
|
91
|
+
self.update()
|
92
|
+
|
93
|
+
def setTextColor(self, light, dark):
|
94
|
+
""" set the color of text
|
95
|
+
|
96
|
+
Parameters
|
97
|
+
----------
|
98
|
+
light, dark: str | QColor | Qt.GlobalColor
|
99
|
+
text color in light/dark theme mode
|
100
|
+
"""
|
101
|
+
self.lightTextColor = QColor(light)
|
102
|
+
self.darkTextColor = QColor(dark)
|
103
|
+
|
104
|
+
setCustomStyleSheet(
|
105
|
+
self,
|
106
|
+
f"CheckBox{{color:{self.lightTextColor.name(QColor.NameFormat.HexArgb)}}}",
|
107
|
+
f"CheckBox{{color:{self.darkTextColor.name(QColor.NameFormat.HexArgb)}}}"
|
108
|
+
)
|
109
|
+
|
110
|
+
def _borderColor(self):
|
111
|
+
if isDarkTheme():
|
112
|
+
map = {
|
113
|
+
CheckBoxState.NORMAL: QColor(255, 255, 255, 141),
|
114
|
+
CheckBoxState.HOVER: QColor(255, 255, 255, 141),
|
115
|
+
CheckBoxState.PRESSED: QColor(255, 255, 255, 40),
|
116
|
+
CheckBoxState.CHECKED : fallbackThemeColor(self.darkCheckedColor),
|
117
|
+
CheckBoxState.CHECKED_HOVER: validColor(self.darkCheckedColor, ThemeColor.DARK_1.color()),
|
118
|
+
CheckBoxState.CHECKED_PRESSED : validColor(self.darkCheckedColor, ThemeColor.DARK_2.color()),
|
119
|
+
CheckBoxState.DISABLED : QColor(255, 255, 255, 41),
|
120
|
+
CheckBoxState.CHECKED_DISABLED : QColor(0, 0, 0, 0)
|
121
|
+
}
|
122
|
+
else:
|
123
|
+
map = {
|
124
|
+
CheckBoxState.NORMAL: QColor(0, 0, 0, 122),
|
125
|
+
CheckBoxState.HOVER: QColor(0, 0, 0, 143),
|
126
|
+
CheckBoxState.PRESSED: QColor(0, 0, 0, 69),
|
127
|
+
CheckBoxState.CHECKED : fallbackThemeColor(self.lightCheckedColor),
|
128
|
+
CheckBoxState.CHECKED_HOVER : validColor(self.lightCheckedColor, ThemeColor.LIGHT_1.color()),
|
129
|
+
CheckBoxState.CHECKED_PRESSED : validColor(self.lightCheckedColor, ThemeColor.LIGHT_2.color()),
|
130
|
+
CheckBoxState.DISABLED : QColor(0, 0, 0, 56),
|
131
|
+
CheckBoxState.CHECKED_DISABLED : QColor(0, 0, 0, 0)
|
132
|
+
}
|
133
|
+
|
134
|
+
return map[self._state()]
|
135
|
+
|
136
|
+
def _backgroundColor(self):
|
137
|
+
if isDarkTheme():
|
138
|
+
map = {
|
139
|
+
CheckBoxState.NORMAL: QColor(0, 0, 0, 26),
|
140
|
+
CheckBoxState.HOVER: QColor(255, 255, 255, 11),
|
141
|
+
CheckBoxState.PRESSED: QColor(255, 255, 255, 18),
|
142
|
+
CheckBoxState.CHECKED: fallbackThemeColor(self.darkCheckedColor),
|
143
|
+
CheckBoxState.CHECKED_HOVER: validColor(self.darkCheckedColor, ThemeColor.DARK_1.color()),
|
144
|
+
CheckBoxState.CHECKED_PRESSED: validColor(self.darkCheckedColor, ThemeColor.DARK_2.color()),
|
145
|
+
CheckBoxState.DISABLED: QColor(0, 0, 0, 0),
|
146
|
+
CheckBoxState.CHECKED_DISABLED: QColor(255, 255, 255, 41)
|
147
|
+
}
|
148
|
+
else:
|
149
|
+
map = {
|
150
|
+
CheckBoxState.NORMAL: QColor(0, 0, 0, 6),
|
151
|
+
CheckBoxState.HOVER: QColor(0, 0, 0, 13),
|
152
|
+
CheckBoxState.PRESSED: QColor(0, 0, 0, 31),
|
153
|
+
CheckBoxState.CHECKED: fallbackThemeColor(self.lightCheckedColor),
|
154
|
+
CheckBoxState.CHECKED_HOVER: validColor(self.lightCheckedColor, ThemeColor.LIGHT_1.color()),
|
155
|
+
CheckBoxState.CHECKED_PRESSED: validColor(self.lightCheckedColor, ThemeColor.LIGHT_2.color()),
|
156
|
+
CheckBoxState.DISABLED: QColor(0, 0, 0, 0),
|
157
|
+
CheckBoxState.CHECKED_DISABLED: QColor(0, 0, 0, 56)
|
158
|
+
}
|
159
|
+
|
160
|
+
return map[self._state()]
|
161
|
+
|
162
|
+
def _state(self):
|
163
|
+
if not self.isEnabled():
|
164
|
+
return CheckBoxState.CHECKED_DISABLED if self.isChecked() else CheckBoxState.DISABLED
|
165
|
+
|
166
|
+
if self.isChecked():
|
167
|
+
if self.isPressed:
|
168
|
+
return CheckBoxState.CHECKED_PRESSED
|
169
|
+
if self.isHover:
|
170
|
+
return CheckBoxState.CHECKED_HOVER
|
171
|
+
|
172
|
+
return CheckBoxState.CHECKED
|
173
|
+
else:
|
174
|
+
if self.isPressed:
|
175
|
+
return CheckBoxState.PRESSED
|
176
|
+
if self.isHover:
|
177
|
+
return CheckBoxState.HOVER
|
178
|
+
|
179
|
+
return CheckBoxState.NORMAL
|
180
|
+
|
181
|
+
def paintEvent(self, e):
|
182
|
+
super().paintEvent(e)
|
183
|
+
painter = QPainter(self)
|
184
|
+
painter.setRenderHints(QPainter.RenderHint.Antialiasing)
|
185
|
+
|
186
|
+
# get the rect of indicator
|
187
|
+
opt = QStyleOptionButton()
|
188
|
+
opt.initFrom(self)
|
189
|
+
rect = self.style().subElementRect(QStyle.SE_CheckBoxIndicator, opt, self)
|
190
|
+
|
191
|
+
# draw shape
|
192
|
+
painter.setPen(self._borderColor())
|
193
|
+
painter.setBrush(self._backgroundColor())
|
194
|
+
painter.drawRoundedRect(rect, 4.5, 4.5)
|
195
|
+
|
196
|
+
if not self.isEnabled():
|
197
|
+
painter.setOpacity(0.8)
|
198
|
+
|
199
|
+
# draw icon
|
200
|
+
if self.checkState() == Qt.Checked:
|
201
|
+
CheckBoxIcon.ACCEPT.render(painter, rect)
|
202
|
+
elif self.checkState() == Qt.PartiallyChecked:
|
203
|
+
CheckBoxIcon.PARTIAL_ACCEPT.render(painter, rect)
|