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,553 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
|
3
|
+
from typing import List, Union
|
4
|
+
|
5
|
+
from PySide6.QtCore import Qt, Property, QPoint, Signal, QSize, QRectF, QUrl
|
6
|
+
from PySide6.QtGui import (QPainter, QPixmap, QPalette, QColor, QFont, QImage, QPainterPath,
|
7
|
+
QImageReader, QBrush, QMovie, QDesktopServices)
|
8
|
+
from PySide6.QtWidgets import QLabel, QWidget, QPushButton, QApplication
|
9
|
+
|
10
|
+
from ...common.exception_handler import exceptionHandler
|
11
|
+
from ...common.overload import singledispatchmethod
|
12
|
+
from ...common.font import setFont, getFont
|
13
|
+
from ...common.style_sheet import FluentStyleSheet, setCustomStyleSheet, setCustomStyleSheet
|
14
|
+
from ...common.config import qconfig, isDarkTheme
|
15
|
+
from .menu import LabelContextMenu
|
16
|
+
|
17
|
+
|
18
|
+
class PixmapLabel(QLabel):
|
19
|
+
""" Label for high dpi pixmap """
|
20
|
+
|
21
|
+
def __init__(self, parent=None):
|
22
|
+
super().__init__(parent)
|
23
|
+
self.__pixmap = QPixmap()
|
24
|
+
|
25
|
+
def setPixmap(self, pixmap: QPixmap):
|
26
|
+
self.__pixmap = pixmap
|
27
|
+
self.setFixedSize(pixmap.size())
|
28
|
+
self.update()
|
29
|
+
|
30
|
+
def pixmap(self):
|
31
|
+
return self.__pixmap
|
32
|
+
|
33
|
+
def paintEvent(self, e):
|
34
|
+
if self.__pixmap.isNull():
|
35
|
+
return super().paintEvent(e)
|
36
|
+
|
37
|
+
painter = QPainter(self)
|
38
|
+
painter.setRenderHints(QPainter.Antialiasing |
|
39
|
+
QPainter.SmoothPixmapTransform)
|
40
|
+
painter.setPen(Qt.NoPen)
|
41
|
+
painter.drawPixmap(self.rect(), self.__pixmap)
|
42
|
+
|
43
|
+
|
44
|
+
class FluentLabelBase(QLabel):
|
45
|
+
""" Fluent label base class
|
46
|
+
|
47
|
+
Constructors
|
48
|
+
------------
|
49
|
+
* FluentLabelBase(`parent`: QWidget = None)
|
50
|
+
* FluentLabelBase(`text`: str, `parent`: QWidget = None)
|
51
|
+
"""
|
52
|
+
|
53
|
+
@singledispatchmethod
|
54
|
+
def __init__(self, parent: QWidget = None):
|
55
|
+
super().__init__(parent)
|
56
|
+
self._init()
|
57
|
+
|
58
|
+
@__init__.register
|
59
|
+
def _(self, text: str, parent: QWidget = None):
|
60
|
+
self.__init__(parent)
|
61
|
+
self.setText(text)
|
62
|
+
|
63
|
+
def _init(self):
|
64
|
+
FluentStyleSheet.LABEL.apply(self)
|
65
|
+
self.setFont(self.getFont())
|
66
|
+
self.setTextColor()
|
67
|
+
qconfig.themeChanged.connect(lambda: self.setTextColor(self.lightColor, self.darkColor))
|
68
|
+
|
69
|
+
self.customContextMenuRequested.connect(self._onContextMenuRequested)
|
70
|
+
return self
|
71
|
+
|
72
|
+
def getFont(self):
|
73
|
+
raise NotImplementedError
|
74
|
+
|
75
|
+
@exceptionHandler()
|
76
|
+
def setTextColor(self, light=QColor(0, 0, 0), dark=QColor(255, 255, 255)):
|
77
|
+
""" set the text color of label
|
78
|
+
|
79
|
+
Parameters
|
80
|
+
----------
|
81
|
+
light, dark: QColor | Qt.GlobalColor | str
|
82
|
+
text color in light/dark mode
|
83
|
+
"""
|
84
|
+
self._lightColor = QColor(light)
|
85
|
+
self._darkColor = QColor(dark)
|
86
|
+
|
87
|
+
setCustomStyleSheet(
|
88
|
+
self,
|
89
|
+
f"FluentLabelBase{{color:{self.lightColor.name(QColor.NameFormat.HexArgb)}}}",
|
90
|
+
f"FluentLabelBase{{color:{self.darkColor.name(QColor.NameFormat.HexArgb)}}}"
|
91
|
+
)
|
92
|
+
|
93
|
+
@Property(QColor)
|
94
|
+
def lightColor(self):
|
95
|
+
return self._lightColor
|
96
|
+
|
97
|
+
@lightColor.setter
|
98
|
+
def lightColor(self, color: QColor):
|
99
|
+
self.setTextColor(color, self.darkColor)
|
100
|
+
|
101
|
+
@Property(QColor)
|
102
|
+
def darkColor(self):
|
103
|
+
return self._darkColor
|
104
|
+
|
105
|
+
@darkColor.setter
|
106
|
+
def darkColor(self, color: QColor):
|
107
|
+
self.setTextColor(self.lightColor, color)
|
108
|
+
|
109
|
+
@Property(int)
|
110
|
+
def pixelFontSize(self):
|
111
|
+
return self.font().pixelSize()
|
112
|
+
|
113
|
+
@pixelFontSize.setter
|
114
|
+
def pixelFontSize(self, size: int):
|
115
|
+
font = self.font()
|
116
|
+
font.setPixelSize(size)
|
117
|
+
self.setFont(font)
|
118
|
+
|
119
|
+
@Property(bool)
|
120
|
+
def strikeOut(self):
|
121
|
+
return self.font().strikeOut()
|
122
|
+
|
123
|
+
@strikeOut.setter
|
124
|
+
def strikeOut(self, isStrikeOut: bool):
|
125
|
+
font = self.font()
|
126
|
+
font.setStrikeOut(isStrikeOut)
|
127
|
+
self.setFont(font)
|
128
|
+
|
129
|
+
@Property(bool)
|
130
|
+
def underline(self):
|
131
|
+
return self.font().underline()
|
132
|
+
|
133
|
+
@underline.setter
|
134
|
+
def underline(self, isUnderline: bool):
|
135
|
+
font = self.font()
|
136
|
+
font.setStyle()
|
137
|
+
font.setUnderline(isUnderline)
|
138
|
+
self.setFont(font)
|
139
|
+
|
140
|
+
def _onContextMenuRequested(self, pos):
|
141
|
+
menu = LabelContextMenu(parent=self)
|
142
|
+
menu.exec(self.mapToGlobal(pos))
|
143
|
+
|
144
|
+
|
145
|
+
class CaptionLabel(FluentLabelBase):
|
146
|
+
""" Caption text label
|
147
|
+
|
148
|
+
Constructors
|
149
|
+
------------
|
150
|
+
* CaptionLabel(`parent`: QWidget = None)
|
151
|
+
* CaptionLabel(`text`: str, `parent`: QWidget = None)
|
152
|
+
"""
|
153
|
+
|
154
|
+
def getFont(self):
|
155
|
+
return getFont(12)
|
156
|
+
|
157
|
+
|
158
|
+
class BodyLabel(FluentLabelBase):
|
159
|
+
""" Body text label
|
160
|
+
|
161
|
+
Constructors
|
162
|
+
------------
|
163
|
+
* BodyLabel(`parent`: QWidget = None)
|
164
|
+
* BodyLabel(`text`: str, `parent`: QWidget = None)
|
165
|
+
"""
|
166
|
+
|
167
|
+
def getFont(self):
|
168
|
+
return getFont(14)
|
169
|
+
|
170
|
+
|
171
|
+
class StrongBodyLabel(FluentLabelBase):
|
172
|
+
""" Strong body text label
|
173
|
+
|
174
|
+
Constructors
|
175
|
+
------------
|
176
|
+
* StrongBodyLabel(`parent`: QWidget = None)
|
177
|
+
* StrongBodyLabel(`text`: str, `parent`: QWidget = None)
|
178
|
+
"""
|
179
|
+
|
180
|
+
def getFont(self):
|
181
|
+
return getFont(14, QFont.DemiBold)
|
182
|
+
|
183
|
+
|
184
|
+
class SubtitleLabel(FluentLabelBase):
|
185
|
+
""" Subtitle text label
|
186
|
+
|
187
|
+
Constructors
|
188
|
+
------------
|
189
|
+
* SubtitleLabel(`parent`: QWidget = None)
|
190
|
+
* SubtitleLabel(`text`: str, `parent`: QWidget = None)
|
191
|
+
"""
|
192
|
+
|
193
|
+
def getFont(self):
|
194
|
+
return getFont(20, QFont.DemiBold)
|
195
|
+
|
196
|
+
|
197
|
+
class TitleLabel(FluentLabelBase):
|
198
|
+
""" Sub title text label
|
199
|
+
|
200
|
+
Constructors
|
201
|
+
------------
|
202
|
+
* TitleLabel(`parent`: QWidget = None)
|
203
|
+
* TitleLabel(`text`: str, `parent`: QWidget = None)
|
204
|
+
"""
|
205
|
+
|
206
|
+
def getFont(self):
|
207
|
+
return getFont(28, QFont.DemiBold)
|
208
|
+
|
209
|
+
|
210
|
+
class LargeTitleLabel(FluentLabelBase):
|
211
|
+
""" Large title text label
|
212
|
+
|
213
|
+
Constructors
|
214
|
+
------------
|
215
|
+
* LargeTitleLabel(`parent`: QWidget = None)
|
216
|
+
* LargeTitleLabel(`text`: str, `parent`: QWidget = None)
|
217
|
+
"""
|
218
|
+
|
219
|
+
def getFont(self):
|
220
|
+
return getFont(40, QFont.DemiBold)
|
221
|
+
|
222
|
+
|
223
|
+
class DisplayLabel(FluentLabelBase):
|
224
|
+
""" Display text label
|
225
|
+
|
226
|
+
Constructors
|
227
|
+
------------
|
228
|
+
* DisplayLabel(`parent`: QWidget = None)
|
229
|
+
* DisplayLabel(`text`: str, `parent`: QWidget = None)
|
230
|
+
"""
|
231
|
+
|
232
|
+
def getFont(self):
|
233
|
+
return getFont(68, QFont.DemiBold)
|
234
|
+
|
235
|
+
|
236
|
+
class ImageLabel(QLabel):
|
237
|
+
""" Image label
|
238
|
+
|
239
|
+
Constructors
|
240
|
+
------------
|
241
|
+
* ImageLabel(`parent`: QWidget = None)
|
242
|
+
* ImageLabel(`image`: str | QImage | QPixmap, `parent`: QWidget = None)
|
243
|
+
"""
|
244
|
+
|
245
|
+
clicked = Signal()
|
246
|
+
|
247
|
+
@singledispatchmethod
|
248
|
+
def __init__(self, parent: QWidget = None):
|
249
|
+
super().__init__(parent)
|
250
|
+
self.image = QImage()
|
251
|
+
self.setBorderRadius(0, 0, 0, 0)
|
252
|
+
self._postInit()
|
253
|
+
|
254
|
+
@__init__.register
|
255
|
+
def _(self, image: str, parent=None):
|
256
|
+
self.__init__(parent)
|
257
|
+
self.setImage(image)
|
258
|
+
self._postInit()
|
259
|
+
|
260
|
+
@__init__.register
|
261
|
+
def _(self, image: QImage, parent=None):
|
262
|
+
self.__init__(parent)
|
263
|
+
self.setImage(image)
|
264
|
+
self._postInit()
|
265
|
+
|
266
|
+
@__init__.register
|
267
|
+
def _(self, image: QPixmap, parent=None):
|
268
|
+
self.__init__(parent)
|
269
|
+
self.setImage(image)
|
270
|
+
self._postInit()
|
271
|
+
|
272
|
+
def _postInit(self):
|
273
|
+
pass
|
274
|
+
|
275
|
+
def _onFrameChanged(self, index: int):
|
276
|
+
self.image = self.movie().currentImage()
|
277
|
+
self.update()
|
278
|
+
|
279
|
+
def setBorderRadius(self, topLeft: int, topRight: int, bottomLeft: int, bottomRight: int):
|
280
|
+
""" set the border radius of image """
|
281
|
+
self._topLeftRadius = topLeft
|
282
|
+
self._topRightRadius = topRight
|
283
|
+
self._bottomLeftRadius = bottomLeft
|
284
|
+
self._bottomRightRadius = bottomRight
|
285
|
+
self.update()
|
286
|
+
|
287
|
+
def setImage(self, image: Union[str, QPixmap, QImage] = None):
|
288
|
+
""" set the image of label """
|
289
|
+
self.image = image or QImage()
|
290
|
+
|
291
|
+
if isinstance(image, str):
|
292
|
+
reader = QImageReader(image)
|
293
|
+
if reader.supportsAnimation():
|
294
|
+
self.setMovie(QMovie(image))
|
295
|
+
else:
|
296
|
+
self.image = reader.read()
|
297
|
+
elif isinstance(image, QPixmap):
|
298
|
+
self.image = image.toImage()
|
299
|
+
|
300
|
+
self.setFixedSize(self.image.size())
|
301
|
+
self.update()
|
302
|
+
|
303
|
+
def scaledToWidth(self, width: int):
|
304
|
+
if self.isNull():
|
305
|
+
return
|
306
|
+
|
307
|
+
h = int(width / self.image.width() * self.image.height())
|
308
|
+
self.setFixedSize(width, h)
|
309
|
+
|
310
|
+
if self.movie():
|
311
|
+
self.movie().setScaledSize(QSize(width, h))
|
312
|
+
|
313
|
+
def scaledToHeight(self, height: int):
|
314
|
+
if self.isNull():
|
315
|
+
return
|
316
|
+
|
317
|
+
w = int(height / self.image.height() * self.image.width())
|
318
|
+
self.setFixedSize(w, height)
|
319
|
+
|
320
|
+
if self.movie():
|
321
|
+
self.movie().setScaledSize(QSize(w, height))
|
322
|
+
|
323
|
+
def setScaledSize(self, size: QSize):
|
324
|
+
if self.isNull():
|
325
|
+
return
|
326
|
+
|
327
|
+
self.setFixedSize(size)
|
328
|
+
|
329
|
+
if self.movie():
|
330
|
+
self.movie().setScaledSize(size)
|
331
|
+
|
332
|
+
def isNull(self):
|
333
|
+
return self.image.isNull()
|
334
|
+
|
335
|
+
def mouseReleaseEvent(self, e):
|
336
|
+
super().mouseReleaseEvent(e)
|
337
|
+
self.clicked.emit()
|
338
|
+
|
339
|
+
def setPixmap(self, pixmap: QPixmap):
|
340
|
+
self.setImage(pixmap)
|
341
|
+
|
342
|
+
def pixmap(self) -> QPixmap:
|
343
|
+
return QPixmap.fromImage(self.image)
|
344
|
+
|
345
|
+
def setMovie(self, movie: QMovie):
|
346
|
+
super().setMovie(movie)
|
347
|
+
self.movie().start()
|
348
|
+
self.image = self.movie().currentImage()
|
349
|
+
self.movie().frameChanged.connect(self._onFrameChanged)
|
350
|
+
|
351
|
+
def paintEvent(self, e):
|
352
|
+
if self.isNull():
|
353
|
+
return
|
354
|
+
|
355
|
+
painter = QPainter(self)
|
356
|
+
painter.setRenderHints(QPainter.Antialiasing)
|
357
|
+
|
358
|
+
path = QPainterPath()
|
359
|
+
w, h = self.width(), self.height()
|
360
|
+
|
361
|
+
# top line
|
362
|
+
path.moveTo(self.topLeftRadius, 0)
|
363
|
+
path.lineTo(w - self.topRightRadius, 0)
|
364
|
+
|
365
|
+
# top right arc
|
366
|
+
d = self.topRightRadius * 2
|
367
|
+
path.arcTo(w - d, 0, d, d, 90, -90)
|
368
|
+
|
369
|
+
# right line
|
370
|
+
path.lineTo(w, h - self.bottomRightRadius)
|
371
|
+
|
372
|
+
# bottom right arc
|
373
|
+
d = self.bottomRightRadius * 2
|
374
|
+
path.arcTo(w - d, h - d, d, d, 0, -90)
|
375
|
+
|
376
|
+
# bottom line
|
377
|
+
path.lineTo(self.bottomLeftRadius, h)
|
378
|
+
|
379
|
+
# bottom left arc
|
380
|
+
d = self.bottomLeftRadius * 2
|
381
|
+
path.arcTo(0, h - d, d, d, -90, -90)
|
382
|
+
|
383
|
+
# left line
|
384
|
+
path.lineTo(0, self.topLeftRadius)
|
385
|
+
|
386
|
+
# top left arc
|
387
|
+
d = self.topLeftRadius * 2
|
388
|
+
path.arcTo(0, 0, d, d, -180, -90)
|
389
|
+
|
390
|
+
# draw image
|
391
|
+
image = self.image.scaled(
|
392
|
+
self.size()*self.devicePixelRatioF(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
|
393
|
+
|
394
|
+
painter.setPen(Qt.NoPen)
|
395
|
+
painter.setClipPath(path)
|
396
|
+
painter.drawImage(self.rect(), image)
|
397
|
+
|
398
|
+
@Property(int)
|
399
|
+
def topLeftRadius(self):
|
400
|
+
return self._topLeftRadius
|
401
|
+
|
402
|
+
@topLeftRadius.setter
|
403
|
+
def topLeftRadius(self, radius: int):
|
404
|
+
self.setBorderRadius(radius, self.topRightRadius, self.bottomLeftRadius, self.bottomRightRadius)
|
405
|
+
|
406
|
+
@Property(int)
|
407
|
+
def topRightRadius(self):
|
408
|
+
return self._topRightRadius
|
409
|
+
|
410
|
+
@topRightRadius.setter
|
411
|
+
def topRightRadius(self, radius: int):
|
412
|
+
self.setBorderRadius(self.topLeftRadius, radius, self.bottomLeftRadius, self.bottomRightRadius)
|
413
|
+
|
414
|
+
@Property(int)
|
415
|
+
def bottomLeftRadius(self):
|
416
|
+
return self._bottomLeftRadius
|
417
|
+
|
418
|
+
@bottomLeftRadius.setter
|
419
|
+
def bottomLeftRadius(self, radius: int):
|
420
|
+
self.setBorderRadius(self.topLeftRadius, self.topRightRadius, radius, self.bottomRightRadius)
|
421
|
+
|
422
|
+
@Property(int)
|
423
|
+
def bottomRightRadius(self):
|
424
|
+
return self._bottomRightRadius
|
425
|
+
|
426
|
+
@bottomRightRadius.setter
|
427
|
+
def bottomRightRadius(self, radius: int):
|
428
|
+
self.setBorderRadius(
|
429
|
+
self.topLeftRadius, self.topRightRadius, self.bottomLeftRadius, radius)
|
430
|
+
|
431
|
+
|
432
|
+
class AvatarWidget(ImageLabel):
|
433
|
+
""" Avatar widget
|
434
|
+
|
435
|
+
Constructors
|
436
|
+
------------
|
437
|
+
* AvatarWidget(`parent`: QWidget = None)
|
438
|
+
* AvatarWidget(`image`: str | QImage | QPixmap, `parent`: QWidget = None)
|
439
|
+
"""
|
440
|
+
|
441
|
+
def _postInit(self):
|
442
|
+
self.setRadius(48)
|
443
|
+
self.lightBackgroundColor = QColor(0, 0, 0, 50)
|
444
|
+
self.darkBackgroundColor = QColor(255, 255, 255, 50)
|
445
|
+
|
446
|
+
def getRadius(self):
|
447
|
+
return self._radius
|
448
|
+
|
449
|
+
def setRadius(self, radius: int):
|
450
|
+
self._radius = radius
|
451
|
+
setFont(self, radius)
|
452
|
+
self.setFixedSize(2*radius, 2*radius)
|
453
|
+
self.update()
|
454
|
+
|
455
|
+
def setBackgroundColor(self, light: QColor, dark: QColor):
|
456
|
+
self.lightBackgroundColor = QColor(light)
|
457
|
+
self.darkBackgroundColor = QColor(light)
|
458
|
+
self.update()
|
459
|
+
|
460
|
+
def paintEvent(self, e):
|
461
|
+
painter = QPainter(self)
|
462
|
+
painter.setRenderHints(QPainter.Antialiasing)
|
463
|
+
|
464
|
+
if not self.isNull():
|
465
|
+
self._drawImageAvatar(painter)
|
466
|
+
else:
|
467
|
+
self._drawTextAvatar(painter)
|
468
|
+
|
469
|
+
def _drawImageAvatar(self, painter: QPainter):
|
470
|
+
# center crop image
|
471
|
+
image = self.image.scaled(
|
472
|
+
self.size()*self.devicePixelRatioF(), Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation) # type: QImage
|
473
|
+
|
474
|
+
iw, ih = image.width(), image.height()
|
475
|
+
d = self.getRadius() * 2 * self.devicePixelRatioF()
|
476
|
+
x, y = (iw - d) / 2, (ih - d) / 2
|
477
|
+
image = image.copy(int(x), int(y), int(d), int(d))
|
478
|
+
|
479
|
+
# draw image
|
480
|
+
path = QPainterPath()
|
481
|
+
path.addEllipse(QRectF(self.rect()))
|
482
|
+
|
483
|
+
painter.setPen(Qt.NoPen)
|
484
|
+
painter.setClipPath(path)
|
485
|
+
painter.drawImage(self.rect(), image)
|
486
|
+
|
487
|
+
def _drawTextAvatar(self, painter: QPainter):
|
488
|
+
if not self.text():
|
489
|
+
return
|
490
|
+
|
491
|
+
painter.setBrush(self.darkBackgroundColor if isDarkTheme() else self.lightBackgroundColor)
|
492
|
+
painter.setPen(Qt.NoPen)
|
493
|
+
painter.drawEllipse(QRectF(self.rect()))
|
494
|
+
|
495
|
+
painter.setFont(self.font())
|
496
|
+
painter.setPen(Qt.white if isDarkTheme() else Qt.black)
|
497
|
+
painter.drawText(self.rect(), Qt.AlignCenter, self.text()[0].upper())
|
498
|
+
|
499
|
+
radius = Property(int, getRadius, setRadius)
|
500
|
+
|
501
|
+
|
502
|
+
class HyperlinkLabel(QPushButton):
|
503
|
+
""" Hyperlink label
|
504
|
+
|
505
|
+
Constructors
|
506
|
+
------------
|
507
|
+
* HyperlinkLabel(`parent`: QWidget = None)
|
508
|
+
* HyperlinkLabel(`text`: str, `parent`: QWidget = None)
|
509
|
+
* HyperlinkLabel(`url`: QUrl, `parent`: QWidget = None)
|
510
|
+
"""
|
511
|
+
|
512
|
+
@singledispatchmethod
|
513
|
+
def __init__(self, parent=None):
|
514
|
+
super().__init__(parent=parent)
|
515
|
+
self._url = QUrl()
|
516
|
+
|
517
|
+
setFont(self, 14)
|
518
|
+
self.setUnderlineVisible(False)
|
519
|
+
FluentStyleSheet.LABEL.apply(self)
|
520
|
+
self.setCursor(Qt.PointingHandCursor)
|
521
|
+
self.clicked.connect(self._onClicked)
|
522
|
+
|
523
|
+
@__init__.register
|
524
|
+
def _(self, text: str, parent=None):
|
525
|
+
self.__init__(parent)
|
526
|
+
self.setText(text)
|
527
|
+
|
528
|
+
@__init__.register
|
529
|
+
def _(self, url: QUrl, text: str, parent=None):
|
530
|
+
self.__init__(parent)
|
531
|
+
self.setText(text)
|
532
|
+
self._url = url
|
533
|
+
|
534
|
+
def getUrl(self) -> QUrl:
|
535
|
+
return self._url
|
536
|
+
|
537
|
+
def setUrl(self, url: Union[QUrl, str]):
|
538
|
+
self._url = QUrl(url)
|
539
|
+
|
540
|
+
def isUnderlineVisible(self):
|
541
|
+
return self._isUnderlineVisible
|
542
|
+
|
543
|
+
def setUnderlineVisible(self, isVisible: bool):
|
544
|
+
self._isUnderlineVisible = isVisible
|
545
|
+
self.setProperty('underline', isVisible)
|
546
|
+
self.setStyle(QApplication.style())
|
547
|
+
|
548
|
+
def _onClicked(self):
|
549
|
+
if self.getUrl().isValid():
|
550
|
+
QDesktopServices.openUrl(self.getUrl())
|
551
|
+
|
552
|
+
url = Property(QUrl, getUrl, setUrl)
|
553
|
+
underlineVisible = Property(bool, isUnderlineVisible, setUnderlineVisible)
|