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.
Files changed (107) hide show
  1. fastuiwidgets/__init__.py +12 -0
  2. fastuiwidgets/_rc/__init__.py +0 -0
  3. fastuiwidgets/_rc/resource.py +98835 -0
  4. fastuiwidgets/common/__init__.py +12 -0
  5. fastuiwidgets/common/animation.py +530 -0
  6. fastuiwidgets/common/auto_wrap.py +164 -0
  7. fastuiwidgets/common/color.py +95 -0
  8. fastuiwidgets/common/config.py +423 -0
  9. fastuiwidgets/common/exception_handler.py +31 -0
  10. fastuiwidgets/common/font.py +38 -0
  11. fastuiwidgets/common/icon.py +703 -0
  12. fastuiwidgets/common/image_utils.py +198 -0
  13. fastuiwidgets/common/overload.py +47 -0
  14. fastuiwidgets/common/router.py +133 -0
  15. fastuiwidgets/common/screen.py +25 -0
  16. fastuiwidgets/common/smooth_scroll.py +141 -0
  17. fastuiwidgets/common/style_sheet.py +512 -0
  18. fastuiwidgets/common/theme_listener.py +27 -0
  19. fastuiwidgets/common/translator.py +14 -0
  20. fastuiwidgets/components/__init__.py +6 -0
  21. fastuiwidgets/components/date_time/__init__.py +4 -0
  22. fastuiwidgets/components/date_time/calendar_picker.py +121 -0
  23. fastuiwidgets/components/date_time/calendar_view.py +671 -0
  24. fastuiwidgets/components/date_time/date_picker.py +245 -0
  25. fastuiwidgets/components/date_time/fast_calendar_view.py +487 -0
  26. fastuiwidgets/components/date_time/picker_base.py +632 -0
  27. fastuiwidgets/components/date_time/time_picker.py +223 -0
  28. fastuiwidgets/components/dialog_box/__init__.py +6 -0
  29. fastuiwidgets/components/dialog_box/color_dialog.py +414 -0
  30. fastuiwidgets/components/dialog_box/dialog.py +167 -0
  31. fastuiwidgets/components/dialog_box/folder_list_dialog.py +307 -0
  32. fastuiwidgets/components/dialog_box/mask_dialog_base.py +120 -0
  33. fastuiwidgets/components/dialog_box/message_box_base.py +92 -0
  34. fastuiwidgets/components/dialog_box/message_dialog.py +65 -0
  35. fastuiwidgets/components/layout/__init__.py +3 -0
  36. fastuiwidgets/components/layout/expand_layout.py +96 -0
  37. fastuiwidgets/components/layout/flow_layout.py +236 -0
  38. fastuiwidgets/components/layout/v_box_layout.py +41 -0
  39. fastuiwidgets/components/material/__init__.py +6 -0
  40. fastuiwidgets/components/material/acrylic_combo_box.py +96 -0
  41. fastuiwidgets/components/material/acrylic_flyout.py +105 -0
  42. fastuiwidgets/components/material/acrylic_line_edit.py +27 -0
  43. fastuiwidgets/components/material/acrylic_menu.py +204 -0
  44. fastuiwidgets/components/material/acrylic_tool_tip.py +39 -0
  45. fastuiwidgets/components/material/acrylic_widget.py +42 -0
  46. fastuiwidgets/components/navigation/__init__.py +9 -0
  47. fastuiwidgets/components/navigation/breadcrumb.py +350 -0
  48. fastuiwidgets/components/navigation/navigation_bar.py +416 -0
  49. fastuiwidgets/components/navigation/navigation_interface.py +268 -0
  50. fastuiwidgets/components/navigation/navigation_panel.py +657 -0
  51. fastuiwidgets/components/navigation/navigation_widget.py +686 -0
  52. fastuiwidgets/components/navigation/pivot.py +272 -0
  53. fastuiwidgets/components/navigation/segmented_widget.py +174 -0
  54. fastuiwidgets/components/settings/__init__.py +8 -0
  55. fastuiwidgets/components/settings/custom_color_setting_card.py +139 -0
  56. fastuiwidgets/components/settings/expand_setting_card.py +390 -0
  57. fastuiwidgets/components/settings/folder_list_setting_card.py +134 -0
  58. fastuiwidgets/components/settings/options_setting_card.py +86 -0
  59. fastuiwidgets/components/settings/setting_card.py +449 -0
  60. fastuiwidgets/components/settings/setting_card_group.py +48 -0
  61. fastuiwidgets/components/widgets/__init__.py +41 -0
  62. fastuiwidgets/components/widgets/acrylic_label.py +261 -0
  63. fastuiwidgets/components/widgets/button.py +1059 -0
  64. fastuiwidgets/components/widgets/card_widget.py +369 -0
  65. fastuiwidgets/components/widgets/check_box.py +203 -0
  66. fastuiwidgets/components/widgets/combo_box.py +556 -0
  67. fastuiwidgets/components/widgets/command_bar.py +636 -0
  68. fastuiwidgets/components/widgets/cycle_list_widget.py +251 -0
  69. fastuiwidgets/components/widgets/flip_view.py +430 -0
  70. fastuiwidgets/components/widgets/flyout.py +521 -0
  71. fastuiwidgets/components/widgets/frameless_window.py +49 -0
  72. fastuiwidgets/components/widgets/icon_widget.py +53 -0
  73. fastuiwidgets/components/widgets/info_badge.py +483 -0
  74. fastuiwidgets/components/widgets/info_bar.py +596 -0
  75. fastuiwidgets/components/widgets/label.py +553 -0
  76. fastuiwidgets/components/widgets/line_edit.py +551 -0
  77. fastuiwidgets/components/widgets/list_view.py +158 -0
  78. fastuiwidgets/components/widgets/menu.py +1318 -0
  79. fastuiwidgets/components/widgets/pips_pager.py +331 -0
  80. fastuiwidgets/components/widgets/progress_bar.py +311 -0
  81. fastuiwidgets/components/widgets/progress_ring.py +212 -0
  82. fastuiwidgets/components/widgets/scroll_area.py +125 -0
  83. fastuiwidgets/components/widgets/scroll_bar.py +673 -0
  84. fastuiwidgets/components/widgets/separator.py +43 -0
  85. fastuiwidgets/components/widgets/slider.py +307 -0
  86. fastuiwidgets/components/widgets/spin_box.py +306 -0
  87. fastuiwidgets/components/widgets/stacked_widget.py +211 -0
  88. fastuiwidgets/components/widgets/state_tool_tip.py +188 -0
  89. fastuiwidgets/components/widgets/switch_button.py +312 -0
  90. fastuiwidgets/components/widgets/tab_view.py +804 -0
  91. fastuiwidgets/components/widgets/table_view.py +360 -0
  92. fastuiwidgets/components/widgets/teaching_tip.py +657 -0
  93. fastuiwidgets/components/widgets/tool_tip.py +460 -0
  94. fastuiwidgets/components/widgets/tree_view.py +216 -0
  95. fastuiwidgets/multimedia/__init__.py +3 -0
  96. fastuiwidgets/multimedia/media_play_bar.py +319 -0
  97. fastuiwidgets/multimedia/media_player.py +124 -0
  98. fastuiwidgets/multimedia/video_widget.py +93 -0
  99. fastuiwidgets/window/__init__.py +2 -0
  100. fastuiwidgets/window/fluent_window.py +413 -0
  101. fastuiwidgets/window/splash_screen.py +92 -0
  102. fastuiwidgets/window/stacked_widget.py +66 -0
  103. python_fastui_widgets-1.0.0.dist-info/METADATA +30 -0
  104. python_fastui_widgets-1.0.0.dist-info/RECORD +107 -0
  105. python_fastui_widgets-1.0.0.dist-info/WHEEL +5 -0
  106. python_fastui_widgets-1.0.0.dist-info/licenses/LICENSE +674 -0
  107. python_fastui_widgets-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,460 @@
1
+ # coding:utf-8
2
+ from enum import Enum
3
+
4
+ from PySide6.QtCore import QEvent, QObject, QPoint, QTimer, Qt, QPropertyAnimation, QModelIndex, QRect
5
+ from PySide6.QtGui import QColor, QHelpEvent
6
+ from PySide6.QtWidgets import (QApplication, QFrame, QGraphicsDropShadowEffect,
7
+ QHBoxLayout, QLabel, QWidget, QAbstractItemView, QStyleOptionViewItem,
8
+ QTableView)
9
+
10
+ from ...common import FluentStyleSheet
11
+ from ...common.screen import getCurrentScreenGeometry
12
+
13
+
14
+ class ToolTipPosition(Enum):
15
+ """ Info bar position """
16
+
17
+ TOP = 0
18
+ BOTTOM = 1
19
+ LEFT = 2
20
+ RIGHT = 3
21
+ TOP_LEFT = 4
22
+ TOP_RIGHT = 5
23
+ BOTTOM_LEFT = 6
24
+ BOTTOM_RIGHT = 7
25
+
26
+
27
+ class ItemViewToolTipType(Enum):
28
+ """ Info bar position """
29
+
30
+ LIST = 0
31
+ TABLE = 1
32
+
33
+
34
+ class ToolTip(QFrame):
35
+ """ Tool tip """
36
+
37
+ def __init__(self, text='', parent=None):
38
+ """
39
+ Parameters
40
+ ----------
41
+ text: str
42
+ the text of tool tip
43
+
44
+ parent: QWidget
45
+ parent widget
46
+ """
47
+ super().__init__(parent=parent)
48
+ self.__text = text
49
+ self.__duration = 1000
50
+
51
+ self.container = self._createContainer()
52
+ self.timer = QTimer(self)
53
+
54
+ self.setLayout(QHBoxLayout())
55
+ self.containerLayout = QHBoxLayout(self.container)
56
+ self.label = QLabel(text, self)
57
+
58
+ # set layout
59
+ self.layout().setContentsMargins(12, 8, 12, 12)
60
+ self.layout().addWidget(self.container)
61
+ self.containerLayout.addWidget(self.label)
62
+ self.containerLayout.setContentsMargins(8, 6, 8, 6)
63
+
64
+ # add opacity effect
65
+ self.opacityAni = QPropertyAnimation(self, b'windowOpacity', self)
66
+ self.opacityAni.setDuration(150)
67
+
68
+ # add shadow
69
+ self.shadowEffect = QGraphicsDropShadowEffect(self)
70
+ self.shadowEffect.setBlurRadius(25)
71
+ self.shadowEffect.setColor(QColor(0, 0, 0, 50))
72
+ self.shadowEffect.setOffset(0, 5)
73
+ self.container.setGraphicsEffect(self.shadowEffect)
74
+
75
+ self.timer.setSingleShot(True)
76
+ self.timer.timeout.connect(self.hide)
77
+
78
+ # set style
79
+ self.setAttribute(Qt.WA_TransparentForMouseEvents)
80
+ self.setAttribute(Qt.WA_TranslucentBackground)
81
+ self.setWindowFlags(Qt.Tool | Qt.FramelessWindowHint)
82
+ self.__setQss()
83
+
84
+ def text(self):
85
+ return self.__text
86
+
87
+ def setText(self, text):
88
+ """ set text on tooltip """
89
+ self.__text = text
90
+ self.label.setText(text)
91
+ self.container.adjustSize()
92
+ self.adjustSize()
93
+
94
+ def duration(self):
95
+ return self.__duration
96
+
97
+ def setDuration(self, duration: int):
98
+ """ set tooltip duration in milliseconds
99
+
100
+ Parameters
101
+ ----------
102
+ duration: int
103
+ display duration in milliseconds, if `duration <= 0`, tooltip won't disappear automatically
104
+ """
105
+ self.__duration = duration
106
+
107
+ def __setQss(self):
108
+ """ set style sheet """
109
+ self.container.setObjectName("container")
110
+ self.label.setObjectName("contentLabel")
111
+ FluentStyleSheet.TOOL_TIP.apply(self)
112
+ self.label.adjustSize()
113
+ self.adjustSize()
114
+
115
+ def _createContainer(self):
116
+ return QFrame(self)
117
+
118
+ def showEvent(self, e):
119
+ self.opacityAni.setStartValue(0)
120
+ self.opacityAni.setEndValue(1)
121
+ self.opacityAni.start()
122
+
123
+ self.timer.stop()
124
+ if self.duration() > 0:
125
+ self.timer.start(self.__duration + self.opacityAni.duration())
126
+
127
+ super().showEvent(e)
128
+
129
+ def hideEvent(self, e):
130
+ self.timer.stop()
131
+ super().hideEvent(e)
132
+
133
+ def adjustPos(self, widget, position: ToolTipPosition):
134
+ """ adjust the position of tooltip relative to widget """
135
+ manager = ToolTipPositionManager.make(position)
136
+ self.move(manager.position(self, widget))
137
+
138
+
139
+ class ToolTipPositionManager:
140
+ """ Tooltip position manager """
141
+
142
+ def position(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
143
+ pos = self._pos(tooltip, parent)
144
+ x, y = pos.x(), pos.y()
145
+
146
+ rect = getCurrentScreenGeometry()
147
+ x = max(rect.left(), min(pos.x(), rect.right() - tooltip.width() - 4))
148
+ y = max(rect.top(), min(pos.y(), rect.bottom() - tooltip.height() - 4))
149
+
150
+ return QPoint(x, y)
151
+
152
+ def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
153
+ raise NotImplementedError
154
+
155
+ @staticmethod
156
+ def make(position: ToolTipPosition):
157
+ """ mask info bar manager according to the display position """
158
+ managers = {
159
+ ToolTipPosition.TOP: TopToolTipManager,
160
+ ToolTipPosition.BOTTOM: BottomToolTipManager,
161
+ ToolTipPosition.LEFT: LeftToolTipManager,
162
+ ToolTipPosition.RIGHT: RightToolTipManager,
163
+ ToolTipPosition.TOP_RIGHT: TopRightToolTipManager,
164
+ ToolTipPosition.BOTTOM_RIGHT: BottomRightToolTipManager,
165
+ ToolTipPosition.TOP_LEFT: TopLeftToolTipManager,
166
+ ToolTipPosition.BOTTOM_LEFT: BottomLeftToolTipManager,
167
+ }
168
+
169
+ if position not in managers:
170
+ raise ValueError(f'`{position}` is an invalid info bar position.')
171
+
172
+ return managers[position]()
173
+
174
+
175
+ class TopToolTipManager(ToolTipPositionManager):
176
+ """ Top tooltip position manager """
177
+
178
+ def _pos(self, tooltip: ToolTip, parent: QWidget):
179
+ pos = parent.mapToGlobal(QPoint())
180
+ x = pos.x() + parent.width()//2 - tooltip.width()//2
181
+ y = pos.y() - tooltip.height()
182
+ return QPoint(x, y)
183
+
184
+
185
+ class BottomToolTipManager(ToolTipPositionManager):
186
+ """ Bottom tooltip position manager """
187
+
188
+ def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
189
+ pos = parent.mapToGlobal(QPoint())
190
+ x = pos.x() + parent.width()//2 - tooltip.width()//2
191
+ y = pos.y() + parent.height()
192
+ return QPoint(x, y)
193
+
194
+
195
+ class LeftToolTipManager(ToolTipPositionManager):
196
+ """ Left tooltip position manager """
197
+
198
+ def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
199
+ pos = parent.mapToGlobal(QPoint())
200
+ x = pos.x() - tooltip.width()
201
+ y = pos.y() + (parent.height() - tooltip.height()) // 2
202
+ return QPoint(x, y)
203
+
204
+
205
+ class RightToolTipManager(ToolTipPositionManager):
206
+ """ Right tooltip position manager """
207
+
208
+ def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
209
+ pos = parent.mapToGlobal(QPoint())
210
+ x = pos.x() + parent.width()
211
+ y = pos.y() + (parent.height() - tooltip.height()) // 2
212
+ return QPoint(x, y)
213
+
214
+
215
+ class TopRightToolTipManager(ToolTipPositionManager):
216
+ """ Top right tooltip position manager """
217
+
218
+ def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
219
+ pos = parent.mapToGlobal(QPoint())
220
+ x = pos.x() + parent.width() - tooltip.width() + \
221
+ tooltip.layout().contentsMargins().right()
222
+ y = pos.y() - tooltip.height()
223
+ return QPoint(x, y)
224
+
225
+
226
+ class TopLeftToolTipManager(ToolTipPositionManager):
227
+ """ Top left tooltip position manager """
228
+
229
+ def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
230
+ pos = parent.mapToGlobal(QPoint())
231
+ x = pos.x() - tooltip.layout().contentsMargins().left()
232
+ y = pos.y() - tooltip.height()
233
+ return QPoint(x, y)
234
+
235
+
236
+ class BottomRightToolTipManager(ToolTipPositionManager):
237
+ """ Bottom right tooltip position manager """
238
+
239
+ def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
240
+ pos = parent.mapToGlobal(QPoint())
241
+ x = pos.x() + parent.width() - tooltip.width() + \
242
+ tooltip.layout().contentsMargins().right()
243
+ y = pos.y() + parent.height()
244
+ return QPoint(x, y)
245
+
246
+
247
+ class BottomLeftToolTipManager(ToolTipPositionManager):
248
+ """ Bottom left tooltip position manager """
249
+
250
+ def _pos(self, tooltip: ToolTip, parent: QWidget) -> QPoint:
251
+ pos = parent.mapToGlobal(QPoint())
252
+ x = pos.x() - tooltip.layout().contentsMargins().left()
253
+ y = pos.y() + parent.height()
254
+ return QPoint(x, y)
255
+
256
+
257
+ class ItemViewToolTipManager(ToolTipPositionManager):
258
+ """ Item view tooltip position manager """
259
+
260
+ def __init__(self, itemRect=QRect()):
261
+ super().__init__()
262
+ self.itemRect = itemRect
263
+
264
+ def _pos(self, tooltip: ToolTip, view: QAbstractItemView) -> QPoint:
265
+ pos = view.mapToGlobal(self.itemRect.topLeft())
266
+ x = pos.x()
267
+ y = pos.y() - tooltip.height() + 10
268
+ return QPoint(x, y)
269
+
270
+ @staticmethod
271
+ def make(tipType: ItemViewToolTipType, itemRect: QRect):
272
+ """ mask info bar manager according to the display tipType """
273
+ managers = {
274
+ ItemViewToolTipType.LIST: ItemViewToolTipManager,
275
+ ItemViewToolTipType.TABLE: TableItemToolTipManager,
276
+ }
277
+
278
+ if tipType not in managers:
279
+ raise ValueError(f'`{tipType}` is an invalid info bar tipType.')
280
+
281
+ return managers[tipType](itemRect)
282
+
283
+
284
+ class TableItemToolTipManager(ItemViewToolTipManager):
285
+ """ Table item view tooltip position manager """
286
+
287
+ def _pos(self, tooltip: ToolTip, view: QTableView) -> QPoint:
288
+ pos = view.mapToGlobal(self.itemRect.topLeft())
289
+ x = pos.x() + view.verticalHeader().isVisible() * view.verticalHeader().width()
290
+ y = pos.y() - tooltip.height() + view.horizontalHeader().isVisible() * view.horizontalHeader().height() + 10
291
+ return QPoint(x, y)
292
+
293
+
294
+
295
+ class ToolTipFilter(QObject):
296
+ """ Tool button with a tool tip """
297
+
298
+ def __init__(self, parent: QWidget, showDelay=300, position=ToolTipPosition.TOP):
299
+ """
300
+ Parameters
301
+ ----------
302
+ parent: QWidget
303
+ the widget to install tool tip
304
+
305
+ showDelay: int
306
+ show tool tip after how long the mouse hovers in milliseconds
307
+
308
+ position: TooltipPosition
309
+ where to show the tooltip
310
+ """
311
+ super().__init__(parent=parent)
312
+ self.isEnter = False
313
+ self._tooltip = None
314
+ self._tooltipDelay = showDelay
315
+ self.position = position
316
+ self.timer = QTimer(self)
317
+ self.timer.setSingleShot(True)
318
+ self.timer.timeout.connect(self.showToolTip)
319
+
320
+ def eventFilter(self, obj: QObject, e: QEvent) -> bool:
321
+ if e.type() == QEvent.ToolTip:
322
+ return True
323
+ elif e.type() in [QEvent.Hide, QEvent.Leave]:
324
+ self.hideToolTip()
325
+ elif e.type() == QEvent.Enter:
326
+ self.isEnter = True
327
+ parent = self.parent() # type: QWidget
328
+ if self._canShowToolTip():
329
+ if self._tooltip is None:
330
+ self._tooltip = self._createToolTip()
331
+
332
+ t = parent.toolTipDuration() if parent.toolTipDuration() > 0 else -1
333
+ self._tooltip.setDuration(t)
334
+
335
+ # show the tool tip after delay
336
+ self.timer.start(self._tooltipDelay)
337
+ elif e.type() == QEvent.MouseButtonPress:
338
+ self.hideToolTip()
339
+
340
+ return super().eventFilter(obj, e)
341
+
342
+ def _createToolTip(self):
343
+ return ToolTip(self.parent().toolTip(), self.parent().window())
344
+
345
+ def hideToolTip(self):
346
+ """ hide tool tip """
347
+ self.isEnter = False
348
+ self.timer.stop()
349
+ if self._tooltip:
350
+ self._tooltip.hide()
351
+
352
+ def showToolTip(self):
353
+ """ show tool tip """
354
+ if not self.isEnter:
355
+ return
356
+
357
+ parent = self.parent() # type: QWidget
358
+ self._tooltip.setText(parent.toolTip())
359
+ self._tooltip.adjustPos(parent, self.position)
360
+ self._tooltip.show()
361
+
362
+ def setToolTipDelay(self, delay: int):
363
+ """ set the delay of tool tip """
364
+ self._tooltipDelay = delay
365
+
366
+ def _canShowToolTip(self) -> bool:
367
+ parent = self.parent() # type: QWidget
368
+ return parent.isWidgetType() and parent.toolTip() and parent.isEnabled()
369
+
370
+
371
+ class ItemViewToolTip(ToolTip):
372
+ """ Item view tool tip """
373
+
374
+ def adjustPos(self, view: QAbstractItemView, itemRect: QRect, tooltipType: ItemViewToolTipType):
375
+ manager = ItemViewToolTipManager.make(tooltipType, itemRect)
376
+ self.move(manager.position(self, view))
377
+
378
+
379
+
380
+ class ItemViewToolTipDelegate(ToolTipFilter):
381
+ """ Item view tool tip """
382
+
383
+ def __init__(self, parent: QAbstractItemView, showDelay=300, tooltipType=ItemViewToolTipType.TABLE):
384
+ super().__init__(parent, showDelay, ToolTipPosition.TOP)
385
+ self.text = ""
386
+ self.currentIndex = None
387
+ self.tooltipDuration = -1
388
+ self.tooltipType = tooltipType
389
+ self.viewport = parent.viewport()
390
+
391
+ parent.installEventFilter(self)
392
+ parent.viewport().installEventFilter(self)
393
+ parent.horizontalScrollBar().valueChanged.connect(self.hideToolTip)
394
+ parent.verticalScrollBar().valueChanged.connect(self.hideToolTip)
395
+
396
+ def eventFilter(self, obj: QObject, e: QEvent) -> bool:
397
+ if obj is self.parent():
398
+ if e.type() in [QEvent.Type.Hide, QEvent.Type.Leave]:
399
+ self.hideToolTip()
400
+ elif e.type() == QEvent.Type.Enter:
401
+ self.isEnter = True
402
+ elif obj is self.viewport:
403
+ if e.type() == QEvent.Type.MouseButtonPress:
404
+ self.hideToolTip()
405
+
406
+ return QObject.eventFilter(self, obj, e)
407
+
408
+ def _createToolTip(self):
409
+ return ItemViewToolTip(self.text, self.parent().window())
410
+
411
+ def showToolTip(self):
412
+ """ show tool tip """
413
+ if not self._tooltip:
414
+ self._tooltip = self._createToolTip()
415
+
416
+ view = self.parent() # type: QAbstractItemView
417
+ self._tooltip.setText(self.text)
418
+
419
+ if self.currentIndex:
420
+ rect = view.visualRect(self.currentIndex)
421
+ else:
422
+ rect = QRect()
423
+
424
+ self._tooltip.adjustPos(view, rect, self.tooltipType)
425
+ self._tooltip.show()
426
+
427
+ def _canShowToolTip(self) -> bool:
428
+ return True
429
+
430
+ def setText(self, text: str):
431
+ self.text = text
432
+ if self._tooltip:
433
+ self._tooltip.setText(text)
434
+
435
+ def setToolTipDuration(self, duration):
436
+ self.tooltipDuration = duration
437
+ if self._tooltip:
438
+ self._tooltip.setDuration(duration)
439
+
440
+ def helpEvent(self, event: QHelpEvent, view: QAbstractItemView, option: QStyleOptionViewItem, index: QModelIndex) -> bool:
441
+ if not event or not view:
442
+ return False
443
+
444
+ if event.type() == QEvent.Type.ToolTip:
445
+ text = index.data(Qt.ItemDataRole.ToolTipRole)
446
+ if not text:
447
+ self.hideToolTip()
448
+ return False
449
+
450
+ self.text = text
451
+ self.currentIndex = index
452
+
453
+ if not self._tooltip:
454
+ self._tooltip = self._createToolTip()
455
+ self._tooltip.setDuration(self.tooltipDuration)
456
+
457
+ # show the tool tip after delay
458
+ self.timer.start(self._tooltipDelay)
459
+
460
+ return True
@@ -0,0 +1,216 @@
1
+ # coding:utf-8
2
+ from PySide6.QtCore import Qt, QSize, QRectF, QModelIndex, QEvent
3
+ from PySide6.QtGui import QPainter, QColor, QPalette
4
+ from PySide6.QtWidgets import QTreeWidget, QStyledItemDelegate, QStyle, QTreeView, QApplication, QStyleOptionViewItem
5
+
6
+ from ...common.style_sheet import FluentStyleSheet, themeColor, isDarkTheme, setCustomStyleSheet
7
+ from ...common.font import getFont
8
+ from ...common.color import autoFallbackThemeColor
9
+ from .check_box import CheckBoxIcon
10
+ from .scroll_area import SmoothScrollDelegate
11
+
12
+
13
+ class TreeItemDelegate(QStyledItemDelegate):
14
+ """ Tree item delegate """
15
+
16
+ def __init__(self, parent: QTreeView):
17
+ super().__init__(parent)
18
+ self.lightCheckedColor = QColor()
19
+ self.darkCheckedColor = QColor()
20
+
21
+ def setCheckedColor(self, light, dark):
22
+ """ set the color of indicator in checked status
23
+
24
+ Parameters
25
+ ----------
26
+ light, dark: str | QColor | Qt.GlobalColor
27
+ color in light/dark theme mode
28
+ """
29
+ self.lightCheckedColor = QColor(light)
30
+ self.darkCheckedColor = QColor(dark)
31
+ self.parent().viewport().update()
32
+
33
+ def paint(self, painter, option, index):
34
+ painter.setRenderHints(
35
+ QPainter.Antialiasing | QPainter.TextAntialiasing)
36
+ super().paint(painter, option, index)
37
+
38
+ if index.data(Qt.CheckStateRole) is not None:
39
+ self._drawCheckBox(painter, option, index)
40
+
41
+ if not (option.state & (QStyle.State_Selected | QStyle.State_MouseOver)):
42
+ return
43
+
44
+ painter.save()
45
+ painter.setPen(Qt.NoPen)
46
+
47
+ # draw background
48
+ h = option.rect.height() - 4
49
+ c = 255 if isDarkTheme() else 0
50
+ painter.setBrush(QColor(c, c, c, 9))
51
+ painter.drawRoundedRect(
52
+ 4, option.rect.y() + 2, self.parent().width() - 8, h, 4, 4)
53
+
54
+ # draw indicator
55
+ if option.state & QStyle.State_Selected and self.parent().horizontalScrollBar().value() == 0:
56
+ painter.setBrush(autoFallbackThemeColor(self.lightCheckedColor, self.darkCheckedColor))
57
+ painter.drawRoundedRect(4, 9+option.rect.y(), 3, h - 13, 1.5, 1.5)
58
+
59
+ painter.restore()
60
+
61
+ def _drawCheckBox(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex):
62
+ painter.save()
63
+ checkState = Qt.CheckState(index.data(Qt.ItemDataRole.CheckStateRole))
64
+
65
+ isDark = isDarkTheme()
66
+
67
+ r = 4.5
68
+ x = option.rect.x() + 23
69
+ y = option.rect.center().y() - 9
70
+ rect = QRectF(x, y, 19, 19)
71
+
72
+ if checkState == Qt.CheckState.Unchecked:
73
+ painter.setBrush(QColor(0, 0, 0, 26)
74
+ if isDark else QColor(0, 0, 0, 6))
75
+ painter.setPen(QColor(255, 255, 255, 142)
76
+ if isDark else QColor(0, 0, 0, 122))
77
+ painter.drawRoundedRect(rect, r, r)
78
+ else:
79
+ color = autoFallbackThemeColor(self.lightCheckedColor, self.darkCheckedColor)
80
+ painter.setPen(color)
81
+ painter.setBrush(color)
82
+ painter.drawRoundedRect(rect, r, r)
83
+
84
+ if checkState == Qt.CheckState.Checked:
85
+ CheckBoxIcon.ACCEPT.render(painter, rect)
86
+ else:
87
+ CheckBoxIcon.PARTIAL_ACCEPT.render(painter, rect)
88
+
89
+ painter.restore()
90
+
91
+
92
+ def initStyleOption(self, option, index):
93
+ super().initStyleOption(option, index)
94
+
95
+ # font
96
+ option.font = index.data(Qt.FontRole) or getFont(13)
97
+
98
+ # text color
99
+ textColor = Qt.white if isDarkTheme() else Qt.black
100
+ textBrush = index.data(Qt.ForegroundRole)
101
+ if textBrush is not None:
102
+ textColor = textBrush.color()
103
+
104
+ option.palette.setColor(QPalette.Text, textColor)
105
+ option.palette.setColor(QPalette.HighlightedText, textColor)
106
+
107
+
108
+ class TreeViewBase:
109
+ """ Tree view base class """
110
+
111
+ def _initView(self):
112
+ self.scrollDelagate = SmoothScrollDelegate(self)
113
+
114
+ self.header().setHighlightSections(False)
115
+ self.header().setDefaultAlignment(Qt.AlignCenter)
116
+
117
+ self.setItemDelegate(TreeItemDelegate(self))
118
+ self.setIconSize(QSize(16, 16))
119
+ self.setMouseTracking(True)
120
+
121
+ FluentStyleSheet.TREE_VIEW.apply(self)
122
+
123
+ def setCheckedColor(self, light, dark):
124
+ """ set the color in checked status
125
+
126
+ Parameters
127
+ ----------
128
+ light, dark: str | QColor | Qt.GlobalColor
129
+ color in light/dark theme mode
130
+ """
131
+ self.itemDelegate().setCheckedColor(light, dark)
132
+
133
+ def drawBranches(self, painter, rect, index):
134
+ rect.moveLeft(15)
135
+ return QTreeView.drawBranches(self, painter, rect, index)
136
+
137
+ def setBorderVisible(self, isVisible: bool):
138
+ """ set the visibility of border """
139
+ self.setProperty("isBorderVisible", isVisible)
140
+ self.setStyle(QApplication.style())
141
+
142
+ def setBorderRadius(self, radius: int):
143
+ """ set the radius of border """
144
+ qss = f"QTreeView{{border-radius: {radius}px}}"
145
+ setCustomStyleSheet(self, qss, qss)
146
+
147
+
148
+ class TreeWidget(TreeViewBase, QTreeWidget):
149
+ """ Tree widget """
150
+
151
+ def __init__(self, parent=None):
152
+ super().__init__(parent=parent)
153
+ self._initView()
154
+
155
+ def viewportEvent(self, event):
156
+ """
157
+ Catch the click event to override the item "expand/collapse" function which is
158
+ still called in the place it was before moving the branches in the drawBranches method.
159
+ """
160
+ if event.type() != QEvent.Type.MouseButtonPress:
161
+ return super().viewportEvent(event)
162
+
163
+ index = self.indexAt(event.pos())
164
+ item = self.itemFromIndex(index)
165
+
166
+ if item is None:
167
+ return super().viewportEvent(event)
168
+
169
+ level = 0
170
+ while item.parent() is not None:
171
+ item = item.parent()
172
+ level += 1
173
+
174
+ indent = level * self.indentation() + 20
175
+ if event.pos().x() > indent and event.pos().x() < indent + 10:
176
+ if self.isExpanded(index):
177
+ self.collapse(index)
178
+ else:
179
+ self.expand(index)
180
+
181
+ return super().viewportEvent(event)
182
+
183
+
184
+ class TreeView(TreeViewBase, QTreeView):
185
+ """ Tree view """
186
+
187
+ def __init__(self, parent=None):
188
+ super().__init__(parent=parent)
189
+ self._initView()
190
+
191
+ def viewportEvent(self, event):
192
+ """
193
+ Catch the click event to override the item "expand/collapse" function which is
194
+ still called in the place it was before moving the branches in the drawBranches method.
195
+ """
196
+ if event.type() != QEvent.Type.MouseButtonPress:
197
+ return super().viewportEvent(event)
198
+
199
+ index = self.indexAt(event.pos())
200
+ if not index.isValid():
201
+ return super().viewportEvent(event)
202
+
203
+ level = 0
204
+ currentIndex = index
205
+ while currentIndex.parent().isValid():
206
+ currentIndex = currentIndex.parent()
207
+ level += 1
208
+
209
+ indent = level * self.indentation() + 20
210
+ if event.pos().x() > indent and event.pos().x() < indent + 10:
211
+ if self.isExpanded(index):
212
+ self.collapse(index)
213
+ else:
214
+ self.expand(index)
215
+
216
+ return super().viewportEvent(event)
@@ -0,0 +1,3 @@
1
+ from .media_player import MediaPlayer, MediaPlayerBase
2
+ from .media_play_bar import MediaPlayBarButton, SimpleMediaPlayBar, StandardMediaPlayBar
3
+ from .video_widget import VideoWidget