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,657 @@
1
+ # coding:utf-8
2
+ from enum import Enum
3
+ from typing import Union
4
+
5
+ from PySide6.QtCore import Qt, QPoint, QObject, QPointF, QTimer, QPropertyAnimation, QEvent
6
+ from PySide6.QtGui import QPainter, QColor, QPainterPath, QIcon, QCursor, QPolygonF, QPixmap, QImage
7
+ from PySide6.QtWidgets import QWidget, QHBoxLayout, QApplication, QGraphicsDropShadowEffect
8
+
9
+ from ...common.icon import FluentIconBase
10
+ from ...common.screen import getCurrentScreenGeometry
11
+ from ...common.style_sheet import isDarkTheme
12
+ from .flyout import FlyoutView, FlyoutViewBase
13
+
14
+
15
+ class TeachingTipTailPosition(Enum):
16
+ """ Teaching tip tail position """
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
+ LEFT_TOP = 8
26
+ LEFT_BOTTOM = 9
27
+ RIGHT_TOP = 10
28
+ RIGHT_BOTTOM = 11
29
+ NONE = 12
30
+
31
+
32
+ class ImagePosition(Enum):
33
+ TOP = 0
34
+ BOTTOM = 1
35
+ LEFT = 2
36
+ RIGHT = 3
37
+
38
+
39
+ class TeachingTipView(FlyoutView):
40
+ """ Teaching tip view """
41
+
42
+ def __init__(self, title: str, content: str, icon: Union[FluentIconBase, QIcon, str] = None,
43
+ image: Union[str, QPixmap, QImage] = None, isClosable=True, tailPosition=TeachingTipTailPosition.BOTTOM,
44
+ parent=None):
45
+ self.manager = TeachingTipManager.make(tailPosition)
46
+ self.hBoxLayout = QHBoxLayout()
47
+ self.hBoxLayout.setContentsMargins(0, 0, 0, 0)
48
+ super().__init__(title, content, icon, image, isClosable, parent)
49
+
50
+ def _adjustImage(self):
51
+ if self.manager.imagePosition() in [ImagePosition.TOP, ImagePosition.BOTTOM]:
52
+ return super()._adjustImage()
53
+
54
+ h = self.vBoxLayout.sizeHint().height() - 2
55
+ self.imageLabel.scaledToHeight(h)
56
+
57
+ def _addImageToLayout(self):
58
+ self.imageLabel.setHidden(self.imageLabel.isNull())
59
+ pos = self.manager.imagePosition()
60
+
61
+ if pos == ImagePosition.TOP:
62
+ self.imageLabel.setBorderRadius(8, 8, 0, 0)
63
+ self.vBoxLayout.insertWidget(0, self.imageLabel)
64
+ elif pos == ImagePosition.BOTTOM:
65
+ self.imageLabel.setBorderRadius(0, 0, 8, 8)
66
+ self.vBoxLayout.addWidget(self.imageLabel)
67
+ elif pos == ImagePosition.LEFT:
68
+ self.vBoxLayout.removeItem(self.vBoxLayout.itemAt(0))
69
+ self.hBoxLayout.addLayout(self.viewLayout)
70
+ self.vBoxLayout.addLayout(self.hBoxLayout)
71
+
72
+ self.imageLabel.setBorderRadius(8, 0, 8, 0)
73
+ self.hBoxLayout.insertWidget(0, self.imageLabel)
74
+ elif pos == ImagePosition.RIGHT:
75
+ self.vBoxLayout.removeItem(self.vBoxLayout.itemAt(0))
76
+ self.hBoxLayout.addLayout(self.viewLayout)
77
+ self.vBoxLayout.addLayout(self.hBoxLayout)
78
+
79
+ self.imageLabel.setBorderRadius(0, 8, 0, 8)
80
+ self.hBoxLayout.addWidget(self.imageLabel)
81
+
82
+ def paintEvent(self, e):
83
+ pass
84
+
85
+
86
+ class TeachTipBubble(QWidget):
87
+ """ Teaching tip bubble """
88
+
89
+ def __init__(self, view: FlyoutViewBase, tailPosition=TeachingTipTailPosition.BOTTOM, parent=None):
90
+ super().__init__(parent=parent)
91
+ self.manager = TeachingTipManager.make(tailPosition)
92
+ self.hBoxLayout = QHBoxLayout(self)
93
+ self.view = view
94
+
95
+ self.manager.doLayout(self)
96
+ self.hBoxLayout.addWidget(self.view)
97
+
98
+ def setView(self, view: QWidget):
99
+ self.hBoxLayout.removeWidget(self.view)
100
+ self.view.deleteLater()
101
+ self.view = view
102
+ self.hBoxLayout.addWidget(view)
103
+
104
+ def paintEvent(self, e):
105
+ painter = QPainter(self)
106
+ painter.setRenderHints(QPainter.Antialiasing)
107
+
108
+ painter.setBrush(
109
+ QColor(40, 40, 40) if isDarkTheme() else QColor(248, 248, 248))
110
+ painter.setPen(
111
+ QColor(23, 23, 23) if isDarkTheme() else QColor(0, 0, 0, 17))
112
+
113
+ self.manager.draw(self, painter)
114
+
115
+
116
+ class TeachingTip(QWidget):
117
+ """ Teaching tip """
118
+
119
+ def __init__(self, view: FlyoutViewBase, target: QWidget, duration=1000,
120
+ tailPosition=TeachingTipTailPosition.BOTTOM, parent=None, isDeleteOnClose=True):
121
+ """
122
+ Parameters
123
+ ----------
124
+ target: QWidget
125
+ the target widget to show tip
126
+
127
+ view: FlyoutViewBase
128
+ teaching tip view
129
+
130
+ duration: int
131
+ the time for teaching tip to display in milliseconds. If duration is less than zero,
132
+ teaching tip will never disappear.
133
+
134
+ tailPosition: TeachingTipTailPosition
135
+ the position of bubble tail
136
+
137
+ parent: QWidget
138
+ parent widget
139
+
140
+ isDeleteOnClose: bool
141
+ whether delete flyout automatically when flyout is closed
142
+ """
143
+ super().__init__(parent=parent)
144
+ self.target = target
145
+ self.duration = duration
146
+ self.isDeleteOnClose = isDeleteOnClose
147
+ self.manager = TeachingTipManager.make(tailPosition)
148
+
149
+ self.hBoxLayout = QHBoxLayout(self)
150
+ self.opacityAni = QPropertyAnimation(self, b'windowOpacity', self)
151
+
152
+ self.bubble = TeachTipBubble(view, tailPosition, self)
153
+
154
+ self.hBoxLayout.setContentsMargins(15, 8, 15, 20)
155
+ self.hBoxLayout.addWidget(self.bubble)
156
+ self.setShadowEffect()
157
+
158
+ # set style
159
+ self.setAttribute(Qt.WA_TranslucentBackground)
160
+ self.setWindowFlags(Qt.Tool | Qt.FramelessWindowHint)
161
+
162
+ if parent and parent.window():
163
+ parent.window().installEventFilter(self)
164
+
165
+ def setShadowEffect(self, blurRadius=35, offset=(0, 8)):
166
+ """ add shadow to dialog """
167
+ color = QColor(0, 0, 0, 80 if isDarkTheme() else 30)
168
+ self.shadowEffect = QGraphicsDropShadowEffect(self.bubble)
169
+ self.shadowEffect.setBlurRadius(blurRadius)
170
+ self.shadowEffect.setOffset(*offset)
171
+ self.shadowEffect.setColor(color)
172
+ self.bubble.setGraphicsEffect(None)
173
+ self.bubble.setGraphicsEffect(self.shadowEffect)
174
+
175
+ def _fadeOut(self):
176
+ """ fade out """
177
+ self.opacityAni.setDuration(167)
178
+ self.opacityAni.setStartValue(1)
179
+ self.opacityAni.setEndValue(0)
180
+ self.opacityAni.finished.connect(self.close)
181
+ self.opacityAni.start()
182
+
183
+ def showEvent(self, e):
184
+ if self.duration >= 0:
185
+ QTimer.singleShot(self.duration, self._fadeOut)
186
+
187
+ self.move(self.manager.position(self))
188
+ self.adjustSize()
189
+ self.opacityAni.setDuration(167)
190
+ self.opacityAni.setStartValue(0)
191
+ self.opacityAni.setEndValue(1)
192
+ self.opacityAni.start()
193
+ super().showEvent(e)
194
+
195
+ def closeEvent(self, e):
196
+ if self.isDeleteOnClose:
197
+ self.deleteLater()
198
+
199
+ super().closeEvent(e)
200
+
201
+ def eventFilter(self, obj, e: QEvent):
202
+ if self.parent() and obj is self.parent().window():
203
+ if e.type() in [QEvent.Resize, QEvent.WindowStateChange, QEvent.Move]:
204
+ self.move(self.manager.position(self))
205
+
206
+ return super().eventFilter(obj, e)
207
+
208
+ def addWidget(self, widget: QWidget, stretch=0, align=Qt.AlignLeft):
209
+ """ add widget to teaching tip """
210
+ self.view.addSpacing(8)
211
+ self.view.addWidget(widget, stretch, align)
212
+
213
+ @property
214
+ def view(self):
215
+ return self.bubble.view
216
+
217
+ def setView(self, view):
218
+ self.bubble.setView(view)
219
+
220
+ @classmethod
221
+ def make(cls, view: FlyoutViewBase, target: QWidget, duration=1000, tailPosition=TeachingTipTailPosition.BOTTOM,
222
+ parent=None, isDeleteOnClose=True):
223
+ """
224
+ Parameters
225
+ ----------
226
+ view: FlyoutViewBase
227
+ teaching tip view
228
+
229
+ target: QWidget
230
+ the target widget to show tip
231
+
232
+ duration: int
233
+ the time for teaching tip to display in milliseconds. If duration is less than zero,
234
+ teaching tip will never disappear.
235
+
236
+ tailPosition: TeachingTipTailPosition
237
+ the position of bubble tail
238
+
239
+ parent: QWidget
240
+ parent widget
241
+
242
+ isDeleteOnClose: bool
243
+ whether delete flyout automatically when flyout is closed
244
+ """
245
+ w = cls(view, target, duration, tailPosition, parent, isDeleteOnClose)
246
+ w.show()
247
+ return w
248
+
249
+ @classmethod
250
+ def create(cls, target: QWidget, title: str, content: str, icon: Union[FluentIconBase, QIcon, str] = None,
251
+ image: Union[str, QPixmap, QImage] = None, isClosable=True, duration=1000,
252
+ tailPosition=TeachingTipTailPosition.BOTTOM, parent=None, isDeleteOnClose=True):
253
+ """
254
+ Parameters
255
+ ----------
256
+ target: QWidget
257
+ the target widget to show tip
258
+
259
+ title: str
260
+ the title of teaching tip
261
+
262
+ content: str
263
+ the content of teaching tip
264
+
265
+ icon: InfoBarIcon | FluentIconBase | QIcon | str
266
+ the icon of teaching tip
267
+
268
+ image: str | QPixmap | QImage
269
+ the image of teaching tip
270
+
271
+ isClosable: bool
272
+ whether to show the close button
273
+
274
+ duraction: int
275
+ the time for teaching tip to display in milliseconds. If duration is less than zero,
276
+ teaching tip will never disappear.
277
+
278
+ parent: QWidget
279
+ parent widget
280
+
281
+ isDeleteOnClose: bool
282
+ whether delete flyout automatically when flyout is closed
283
+ """
284
+ view = TeachingTipView(title, content, icon, image, isClosable, tailPosition)
285
+ w = cls.make(view, target, duration, tailPosition, parent, isDeleteOnClose)
286
+ view.closed.connect(w.close)
287
+ return w
288
+
289
+
290
+ class PopupTeachingTip(TeachingTip):
291
+ """ Pop up teaching tip """
292
+
293
+ def __init__(self, view: FlyoutViewBase, target: QWidget, duration=1000,
294
+ tailPosition=TeachingTipTailPosition.BOTTOM, parent=None, isDeleteOnClose=True):
295
+ super().__init__(view, target, duration, tailPosition, parent, isDeleteOnClose)
296
+ self.setWindowFlags(Qt.Popup | Qt.FramelessWindowHint | Qt.NoDropShadowWindowHint)
297
+
298
+
299
+ class TeachingTipManager(QObject):
300
+ """ Teaching tip manager """
301
+
302
+ def __init__(self):
303
+ super().__init__()
304
+
305
+ def doLayout(self, tip: TeachTipBubble):
306
+ """ manage the layout of tip """
307
+ tip.hBoxLayout.setContentsMargins(0, 0, 0, 0)
308
+
309
+ def imagePosition(self):
310
+ return ImagePosition.TOP
311
+
312
+ def position(self, tip: TeachingTip) -> QPoint:
313
+ pos = self._pos(tip)
314
+ x, y = pos.x(), pos.y()
315
+
316
+ rect = getCurrentScreenGeometry()
317
+ x = max(rect.left(), min(pos.x(), rect.right() - tip.width() - 4))
318
+ y = max(rect.top(), min(pos.y(), rect.bottom() - tip.height() - 4))
319
+
320
+ return QPoint(x, y)
321
+
322
+ def draw(self, tip: TeachTipBubble, painter: QPainter):
323
+ """ draw the shape of bubble """
324
+ rect = tip.rect().adjusted(1, 1, -1, -1)
325
+ painter.drawRoundedRect(rect, 8, 8)
326
+
327
+ def _pos(self, tip: TeachingTip):
328
+ """ return the poisition of tip """
329
+ return tip.pos()
330
+
331
+ @staticmethod
332
+ def make(position: TeachingTipTailPosition):
333
+ """ mask teaching tip manager according to the display position """
334
+ managers = {
335
+ TeachingTipTailPosition.TOP: TopTailTeachingTipManager,
336
+ TeachingTipTailPosition.BOTTOM: BottomTailTeachingTipManager,
337
+ TeachingTipTailPosition.LEFT: LeftTailTeachingTipManager,
338
+ TeachingTipTailPosition.RIGHT: RightTailTeachingTipManager,
339
+ TeachingTipTailPosition.TOP_RIGHT: TopRightTailTeachingTipManager,
340
+ TeachingTipTailPosition.BOTTOM_RIGHT: BottomRightTailTeachingTipManager,
341
+ TeachingTipTailPosition.TOP_LEFT: TopLeftTailTeachingTipManager,
342
+ TeachingTipTailPosition.BOTTOM_LEFT: BottomLeftTailTeachingTipManager,
343
+ TeachingTipTailPosition.LEFT_TOP: LeftTopTailTeachingTipManager,
344
+ TeachingTipTailPosition.LEFT_BOTTOM: LeftBottomTailTeachingTipManager,
345
+ TeachingTipTailPosition.RIGHT_TOP: RightTopTailTeachingTipManager,
346
+ TeachingTipTailPosition.RIGHT_BOTTOM: RightBottomTailTeachingTipManager,
347
+ TeachingTipTailPosition.NONE: TeachingTipManager,
348
+ }
349
+
350
+ if position not in managers:
351
+ raise ValueError(
352
+ f'`{position}` is an invalid teaching tip position.')
353
+
354
+ return managers[position]()
355
+
356
+
357
+ class TopTailTeachingTipManager(TeachingTipManager):
358
+ """ Top tail teaching tip manager """
359
+
360
+ def doLayout(self, tip):
361
+ tip.hBoxLayout.setContentsMargins(0, 8, 0, 0)
362
+
363
+ def imagePosition(self):
364
+ return ImagePosition.BOTTOM
365
+
366
+ def draw(self, tip, painter):
367
+ w, h = tip.width(), tip.height()
368
+ pt = tip.hBoxLayout.contentsMargins().top()
369
+
370
+ path = QPainterPath()
371
+ path.addRoundedRect(1, pt, w - 2, h - pt - 1, 8, 8)
372
+ path.addPolygon(
373
+ QPolygonF([QPointF(w/2 - 7, pt), QPointF(w/2, 1), QPointF(w/2 + 7, pt)]))
374
+
375
+ painter.drawPath(path.simplified())
376
+
377
+ def _pos(self, tip: TeachingTip):
378
+ target = tip.target
379
+ pos = target.mapToGlobal(QPoint(0, target.height()))
380
+ x = pos.x() + target.width()//2 - tip.sizeHint().width()//2
381
+ y = pos.y() - tip.layout().contentsMargins().top()
382
+ return QPoint(x, y)
383
+
384
+
385
+ class BottomTailTeachingTipManager(TeachingTipManager):
386
+ """ Bottom tail teaching tip manager """
387
+
388
+ def doLayout(self, tip):
389
+ tip.hBoxLayout.setContentsMargins(0, 0, 0, 8)
390
+
391
+ def draw(self, tip, painter):
392
+ w, h = tip.width(), tip.height()
393
+ pb = tip.hBoxLayout.contentsMargins().bottom()
394
+
395
+ path = QPainterPath()
396
+ path.addRoundedRect(1, 1, w - 2, h - pb - 1, 8, 8)
397
+ path.addPolygon(
398
+ QPolygonF([QPointF(w/2 - 7, h - pb), QPointF(w/2, h - 1), QPointF(w/2 + 7, h - pb)]))
399
+
400
+ painter.drawPath(path.simplified())
401
+
402
+ def _pos(self, tip: TeachingTip):
403
+ target = tip.target
404
+ pos = target.mapToGlobal(QPoint())
405
+ x = pos.x() + target.width()//2 - tip.sizeHint().width()//2
406
+ y = pos.y() - tip.sizeHint().height() + tip.layout().contentsMargins().bottom()
407
+ return QPoint(x, y)
408
+
409
+
410
+ class LeftTailTeachingTipManager(TeachingTipManager):
411
+ """ Left tail teaching tip manager """
412
+
413
+ def doLayout(self, tip):
414
+ tip.hBoxLayout.setContentsMargins(8, 0, 0, 0)
415
+
416
+ def imagePosition(self):
417
+ return ImagePosition.RIGHT
418
+
419
+ def draw(self, tip, painter):
420
+ w, h = tip.width(), tip.height()
421
+ pl = 8
422
+
423
+ path = QPainterPath()
424
+ path.addRoundedRect(pl, 1, w - pl - 2, h - 2, 8, 8)
425
+ path.addPolygon(
426
+ QPolygonF([QPointF(pl, h/2 - 7), QPointF(1, h/2), QPointF(pl, h/2 + 7)]))
427
+
428
+ painter.drawPath(path.simplified())
429
+
430
+ def _pos(self, tip: TeachingTip):
431
+ target = tip.target
432
+ m = tip.layout().contentsMargins()
433
+ pos = target.mapToGlobal(QPoint(target.width(), 0))
434
+ x = pos.x() - m.left()
435
+ y = pos.y() - tip.view.sizeHint().height()//2 + target.height()//2 - m.top()
436
+ return QPoint(x, y)
437
+
438
+
439
+ class RightTailTeachingTipManager(TeachingTipManager):
440
+ """ Left tail teaching tip manager """
441
+
442
+ def doLayout(self, tip):
443
+ tip.hBoxLayout.setContentsMargins(0, 0, 8, 0)
444
+
445
+ def imagePosition(self):
446
+ return ImagePosition.LEFT
447
+
448
+ def draw(self, tip, painter):
449
+ w, h = tip.width(), tip.height()
450
+ pr = 8
451
+
452
+ path = QPainterPath()
453
+ path.addRoundedRect(1, 1, w - pr - 1, h - 2, 8, 8)
454
+ path.addPolygon(
455
+ QPolygonF([QPointF(w - pr, h/2 - 7), QPointF(w - 1, h/2), QPointF(w - pr, h/2 + 7)]))
456
+
457
+ painter.drawPath(path.simplified())
458
+
459
+ def _pos(self, tip: TeachingTip):
460
+ target = tip.target
461
+ m = tip.layout().contentsMargins()
462
+ pos = target.mapToGlobal(QPoint(0, 0))
463
+ x = pos.x() - tip.sizeHint().width() + m.right()
464
+ y = pos.y() - tip.view.sizeHint().height()//2 + target.height()//2 - m.top()
465
+ return QPoint(x, y)
466
+
467
+
468
+ class TopLeftTailTeachingTipManager(TopTailTeachingTipManager):
469
+ """ Top left tail teaching tip manager """
470
+
471
+ def draw(self, tip, painter):
472
+ w, h = tip.width(), tip.height()
473
+ pt = tip.hBoxLayout.contentsMargins().top()
474
+
475
+ path = QPainterPath()
476
+ path.addRoundedRect(1, pt, w - 2, h - pt - 1, 8, 8)
477
+ path.addPolygon(
478
+ QPolygonF([QPointF(20, pt), QPointF(27, 1), QPointF(34, pt)]))
479
+
480
+ painter.drawPath(path.simplified())
481
+
482
+ def _pos(self, tip: TeachingTip):
483
+ target = tip.target
484
+ pos = target.mapToGlobal(QPoint(0, target.height()))
485
+ x = pos.x() - tip.layout().contentsMargins().left()
486
+ y = pos.y() - tip.layout().contentsMargins().top()
487
+ return QPoint(x, y)
488
+
489
+
490
+ class TopRightTailTeachingTipManager(TopTailTeachingTipManager):
491
+ """ Top right tail teaching tip manager """
492
+
493
+ def draw(self, tip, painter):
494
+ w, h = tip.width(), tip.height()
495
+ pt = tip.hBoxLayout.contentsMargins().top()
496
+
497
+ path = QPainterPath()
498
+ path.addRoundedRect(1, pt, w - 2, h - pt - 1, 8, 8)
499
+ path.addPolygon(
500
+ QPolygonF([QPointF(w - 20, pt), QPointF(w - 27, 1), QPointF(w - 34, pt)]))
501
+
502
+ painter.drawPath(path.simplified())
503
+
504
+ def _pos(self, tip: TeachingTip):
505
+ target = tip.target
506
+ pos = target.mapToGlobal(QPoint(target.width(), target.height()))
507
+ x = pos.x() - tip.sizeHint().width() + tip.layout().contentsMargins().left()
508
+ y = pos.y() - tip.layout().contentsMargins().top()
509
+ return QPoint(x, y)
510
+
511
+
512
+ class BottomLeftTailTeachingTipManager(BottomTailTeachingTipManager):
513
+ """ Bottom left tail teaching tip manager """
514
+
515
+ def draw(self, tip, painter):
516
+ w, h = tip.width(), tip.height()
517
+ pb = tip.hBoxLayout.contentsMargins().bottom()
518
+
519
+ path = QPainterPath()
520
+ path.addRoundedRect(1, 1, w - 2, h - pb - 1, 8, 8)
521
+ path.addPolygon(
522
+ QPolygonF([QPointF(20, h - pb), QPointF(27, h - 1), QPointF(34, h - pb)]))
523
+
524
+ painter.drawPath(path.simplified())
525
+
526
+ def _pos(self, tip: TeachingTip):
527
+ target = tip.target
528
+ pos = target.mapToGlobal(QPoint())
529
+ x = pos.x() - tip.layout().contentsMargins().left()
530
+ y = pos.y() - tip.sizeHint().height() + tip.layout().contentsMargins().bottom()
531
+ return QPoint(x, y)
532
+
533
+
534
+ class BottomRightTailTeachingTipManager(BottomTailTeachingTipManager):
535
+ """ Bottom right tail teaching tip manager """
536
+
537
+ def draw(self, tip, painter):
538
+ w, h = tip.width(), tip.height()
539
+ pb = tip.hBoxLayout.contentsMargins().bottom()
540
+
541
+ path = QPainterPath()
542
+ path.addRoundedRect(1, 1, w - 2, h - pb - 1, 8, 8)
543
+ path.addPolygon(
544
+ QPolygonF([QPointF(w - 20, h - pb), QPointF(w - 27, h - 1), QPointF(w - 34, h - pb)]))
545
+
546
+ painter.drawPath(path.simplified())
547
+
548
+ def _pos(self, tip: TeachingTip):
549
+ target = tip.target
550
+ pos = target.mapToGlobal(QPoint(target.width(), 0))
551
+ x = pos.x() - tip.sizeHint().width() + tip.layout().contentsMargins().left()
552
+ y = pos.y() - tip.sizeHint().height() + tip.layout().contentsMargins().bottom()
553
+ return QPoint(x, y)
554
+
555
+
556
+ class LeftTopTailTeachingTipManager(LeftTailTeachingTipManager):
557
+ """ Left top tail teaching tip manager """
558
+
559
+ def imagePosition(self):
560
+ return ImagePosition.BOTTOM
561
+
562
+ def draw(self, tip, painter):
563
+ w, h = tip.width(), tip.height()
564
+ pl = 8
565
+
566
+ path = QPainterPath()
567
+ path.addRoundedRect(pl, 1, w - pl - 2, h - 2, 8, 8)
568
+ path.addPolygon(
569
+ QPolygonF([QPointF(pl, 10), QPointF(1, 17), QPointF(pl, 24)]))
570
+
571
+ painter.drawPath(path.simplified())
572
+
573
+ def _pos(self, tip: TeachingTip):
574
+ target = tip.target
575
+ m = tip.layout().contentsMargins()
576
+ pos = target.mapToGlobal(QPoint(target.width(), 0))
577
+ x = pos.x() - m.left()
578
+ y = pos.y() - m.top()
579
+ return QPoint(x, y)
580
+
581
+
582
+ class LeftBottomTailTeachingTipManager(LeftTailTeachingTipManager):
583
+ """ Left bottom tail teaching tip manager """
584
+
585
+ def imagePosition(self):
586
+ return ImagePosition.TOP
587
+
588
+ def draw(self, tip, painter):
589
+ w, h = tip.width(), tip.height()
590
+ pl = 9
591
+
592
+ path = QPainterPath()
593
+ path.addRoundedRect(pl, 1, w - pl - 1, h - 2, 8, 8)
594
+ path.addPolygon(
595
+ QPolygonF([QPointF(pl, h - 10), QPointF(1, h - 17), QPointF(pl, h - 24)]))
596
+
597
+ painter.drawPath(path.simplified())
598
+
599
+ def _pos(self, tip: TeachingTip):
600
+ target = tip.target
601
+ m = tip.layout().contentsMargins()
602
+ pos = target.mapToGlobal(QPoint(target.width(), target.height()))
603
+ x = pos.x() - m.left()
604
+ y = pos.y() - tip.sizeHint().height() + m.bottom()
605
+ return QPoint(x, y)
606
+
607
+
608
+ class RightTopTailTeachingTipManager(RightTailTeachingTipManager):
609
+ """ Right top tail teaching tip manager """
610
+
611
+ def imagePosition(self):
612
+ return ImagePosition.BOTTOM
613
+
614
+ def draw(self, tip, painter):
615
+ w, h = tip.width(), tip.height()
616
+ pr = 8
617
+
618
+ path = QPainterPath()
619
+ path.addRoundedRect(1, 1, w - pr - 1, h - 2, 8, 8)
620
+ path.addPolygon(
621
+ QPolygonF([QPointF(w - pr, 10), QPointF(w - 1, 17), QPointF(w - pr, 24)]))
622
+
623
+ painter.drawPath(path.simplified())
624
+
625
+ def _pos(self, tip: TeachingTip):
626
+ target = tip.target
627
+ m = tip.layout().contentsMargins()
628
+ pos = target.mapToGlobal(QPoint(0, 0))
629
+ x = pos.x() - tip.sizeHint().width() + m.right()
630
+ y = pos.y() - m.top()
631
+ return QPoint(x, y)
632
+
633
+
634
+ class RightBottomTailTeachingTipManager(RightTailTeachingTipManager):
635
+ """ Right bottom tail teaching tip manager """
636
+
637
+ def imagePosition(self):
638
+ return ImagePosition.TOP
639
+
640
+ def draw(self, tip, painter):
641
+ w, h = tip.width(), tip.height()
642
+ pr = 8
643
+
644
+ path = QPainterPath()
645
+ path.addRoundedRect(1, 1, w - pr - 1, h - 2, 8, 8)
646
+ path.addPolygon(
647
+ QPolygonF([QPointF(w - pr, h-10), QPointF(w - 1, h-17), QPointF(w - pr, h-24)]))
648
+
649
+ painter.drawPath(path.simplified())
650
+
651
+ def _pos(self, tip: TeachingTip):
652
+ target = tip.target
653
+ m = tip.layout().contentsMargins()
654
+ pos = target.mapToGlobal(QPoint(0, target.height()))
655
+ x = pos.x() - tip.sizeHint().width() + m.right()
656
+ y = pos.y() - tip.sizeHint().height() + m.bottom()
657
+ return QPoint(x, y)