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,65 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
from PySide6.QtCore import Signal
|
3
|
+
from PySide6.QtWidgets import QLabel, QPushButton, QDialog
|
4
|
+
|
5
|
+
from ...common.auto_wrap import TextWrap
|
6
|
+
from ...common.style_sheet import FluentStyleSheet
|
7
|
+
from .mask_dialog_base import MaskDialogBase
|
8
|
+
|
9
|
+
|
10
|
+
class MessageDialog(MaskDialogBase):
|
11
|
+
""" Win10 style message dialog box with a mask """
|
12
|
+
|
13
|
+
yesSignal = Signal()
|
14
|
+
cancelSignal = Signal()
|
15
|
+
|
16
|
+
def __init__(self, title: str, content: str, parent):
|
17
|
+
super().__init__(parent=parent)
|
18
|
+
self.content = content
|
19
|
+
self.titleLabel = QLabel(title, self.widget)
|
20
|
+
self.contentLabel = QLabel(content, self.widget)
|
21
|
+
self.yesButton = QPushButton(self.tr('OK'), self.widget)
|
22
|
+
self.cancelButton = QPushButton(self.tr('Cancel'), self.widget)
|
23
|
+
self.__initWidget()
|
24
|
+
|
25
|
+
def __initWidget(self):
|
26
|
+
""" initialize widgets """
|
27
|
+
self.windowMask.resize(self.size())
|
28
|
+
self.widget.setMaximumWidth(540)
|
29
|
+
self.titleLabel.move(24, 24)
|
30
|
+
self.contentLabel.move(24, 56)
|
31
|
+
self.contentLabel.setText(TextWrap.wrap(self.content, 71)[0])
|
32
|
+
|
33
|
+
self.__setQss()
|
34
|
+
self.__initLayout()
|
35
|
+
|
36
|
+
# connect signal to slot
|
37
|
+
self.yesButton.clicked.connect(self.__onYesButtonClicked)
|
38
|
+
self.cancelButton.clicked.connect(self.__onCancelButtonClicked)
|
39
|
+
|
40
|
+
def __initLayout(self):
|
41
|
+
""" initialize layout """
|
42
|
+
self.contentLabel.adjustSize()
|
43
|
+
self.widget.setFixedSize(48+self.contentLabel.width(),
|
44
|
+
self.contentLabel.y() + self.contentLabel.height()+92)
|
45
|
+
self.yesButton.resize((self.widget.width() - 54) // 2, 32)
|
46
|
+
self.cancelButton.resize(self.yesButton.width(), 32)
|
47
|
+
self.yesButton.move(24, self.widget.height()-56)
|
48
|
+
self.cancelButton.move(
|
49
|
+
self.widget.width()-24-self.cancelButton.width(), self.widget.height()-56)
|
50
|
+
|
51
|
+
def __onCancelButtonClicked(self):
|
52
|
+
self.cancelSignal.emit()
|
53
|
+
self.reject()
|
54
|
+
|
55
|
+
def __onYesButtonClicked(self):
|
56
|
+
self.setEnabled(False)
|
57
|
+
self.yesSignal.emit()
|
58
|
+
self.accept()
|
59
|
+
|
60
|
+
def __setQss(self):
|
61
|
+
""" set style sheet """
|
62
|
+
self.windowMask.setObjectName('windowMask')
|
63
|
+
self.titleLabel.setObjectName('titleLabel')
|
64
|
+
self.contentLabel.setObjectName('contentLabel')
|
65
|
+
FluentStyleSheet.MESSAGE_DIALOG.apply(self)
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
from PySide6.QtCore import QSize, QPoint, Qt, QEvent, QRect
|
3
|
+
from PySide6.QtGui import QResizeEvent
|
4
|
+
from PySide6.QtWidgets import QLayout, QWidget
|
5
|
+
|
6
|
+
|
7
|
+
class ExpandLayout(QLayout):
|
8
|
+
""" Expand layout """
|
9
|
+
|
10
|
+
def __init__(self, parent=None):
|
11
|
+
super().__init__(parent)
|
12
|
+
self.__items = []
|
13
|
+
self.__widgets = []
|
14
|
+
|
15
|
+
def addWidget(self, widget: QWidget):
|
16
|
+
if widget in self.__widgets:
|
17
|
+
return
|
18
|
+
|
19
|
+
self.__widgets.append(widget)
|
20
|
+
widget.installEventFilter(self)
|
21
|
+
|
22
|
+
def addItem(self, item):
|
23
|
+
self.__items.append(item)
|
24
|
+
|
25
|
+
def count(self):
|
26
|
+
return len(self.__items)
|
27
|
+
|
28
|
+
def itemAt(self, index):
|
29
|
+
if 0 <= index < len(self.__items):
|
30
|
+
return self.__items[index]
|
31
|
+
|
32
|
+
return None
|
33
|
+
|
34
|
+
def takeAt(self, index):
|
35
|
+
if 0 <= index < len(self.__items):
|
36
|
+
self.__widgets.pop(index)
|
37
|
+
return self.__items.pop(index)
|
38
|
+
|
39
|
+
return None
|
40
|
+
|
41
|
+
def expandingDirections(self):
|
42
|
+
return Qt.Vertical
|
43
|
+
|
44
|
+
def hasHeightForWidth(self):
|
45
|
+
return True
|
46
|
+
|
47
|
+
def heightForWidth(self, width):
|
48
|
+
""" get the minimal height according to width """
|
49
|
+
return self.__doLayout(QRect(0, 0, width, 0), False)
|
50
|
+
|
51
|
+
def setGeometry(self, rect):
|
52
|
+
super().setGeometry(rect)
|
53
|
+
self.__doLayout(rect, True)
|
54
|
+
|
55
|
+
def sizeHint(self):
|
56
|
+
return self.minimumSize()
|
57
|
+
|
58
|
+
def minimumSize(self):
|
59
|
+
size = QSize()
|
60
|
+
|
61
|
+
for w in self.__widgets:
|
62
|
+
size = size.expandedTo(w.minimumSize())
|
63
|
+
|
64
|
+
m = self.contentsMargins()
|
65
|
+
size += QSize(m.left()+m.right(), m.top()+m.bottom())
|
66
|
+
|
67
|
+
return size
|
68
|
+
|
69
|
+
def __doLayout(self, rect, move):
|
70
|
+
""" adjust widgets position according to the window size """
|
71
|
+
margin = self.contentsMargins()
|
72
|
+
x = rect.x() + margin.left()
|
73
|
+
y = rect.y() + margin.top()
|
74
|
+
width = rect.width() - margin.left() - margin.right()
|
75
|
+
|
76
|
+
for i, w in enumerate(self.__widgets):
|
77
|
+
if w.isHidden():
|
78
|
+
continue
|
79
|
+
|
80
|
+
y += (i>0)*self.spacing()
|
81
|
+
if move:
|
82
|
+
w.setGeometry(QRect(QPoint(x, y), QSize(width, w.height())))
|
83
|
+
|
84
|
+
y += w.height()
|
85
|
+
|
86
|
+
return y - rect.y()
|
87
|
+
|
88
|
+
def eventFilter(self, obj, e):
|
89
|
+
if obj in self.__widgets:
|
90
|
+
if e.type() == QEvent.Resize:
|
91
|
+
ds = e.size() - e.oldSize() # type:QSize
|
92
|
+
if ds.height() != 0 and ds.width() == 0:
|
93
|
+
w = self.parentWidget()
|
94
|
+
w.resize(w.width(), w.height() + ds.height())
|
95
|
+
|
96
|
+
return super().eventFilter(obj, e)
|
@@ -0,0 +1,236 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
from typing import List
|
3
|
+
|
4
|
+
from PySide6.QtCore import QSize, QPoint, Qt, QRect, QPropertyAnimation, QParallelAnimationGroup, QEasingCurve, QEvent, QTimer, QObject
|
5
|
+
from PySide6.QtWidgets import QLayout, QWidgetItem, QLayoutItem
|
6
|
+
|
7
|
+
|
8
|
+
class FlowLayout(QLayout):
|
9
|
+
""" Flow layout """
|
10
|
+
|
11
|
+
def __init__(self, parent=None, needAni=False, isTight=False):
|
12
|
+
"""
|
13
|
+
Parameters
|
14
|
+
----------
|
15
|
+
parent:
|
16
|
+
parent window or layout
|
17
|
+
|
18
|
+
needAni: bool
|
19
|
+
whether to add moving animation
|
20
|
+
|
21
|
+
isTight: bool
|
22
|
+
whether to use the tight layout when widgets are hidden
|
23
|
+
"""
|
24
|
+
super().__init__(parent)
|
25
|
+
self._items = [] # type: List[QLayoutItem]
|
26
|
+
self._anis = [] # type: List[QPropertyAnimation]
|
27
|
+
self._aniGroup = QParallelAnimationGroup(self)
|
28
|
+
self._verticalSpacing = 10
|
29
|
+
self._horizontalSpacing = 10
|
30
|
+
self.duration = 300
|
31
|
+
self.ease = QEasingCurve.Linear
|
32
|
+
self.needAni = needAni
|
33
|
+
self.isTight = isTight
|
34
|
+
self._deBounceTimer = QTimer(self)
|
35
|
+
self._deBounceTimer.setSingleShot(True)
|
36
|
+
self._deBounceTimer.timeout.connect(lambda: self._doLayout(self.geometry(), True))
|
37
|
+
self._wParent = None
|
38
|
+
self._isInstalledEventFilter = False
|
39
|
+
|
40
|
+
def addItem(self, item):
|
41
|
+
self._items.append(item)
|
42
|
+
|
43
|
+
def insertItem(self, index, item):
|
44
|
+
self._items.insert(index, item)
|
45
|
+
|
46
|
+
def addWidget(self, w):
|
47
|
+
super().addWidget(w)
|
48
|
+
self._onWidgetAdded(w)
|
49
|
+
|
50
|
+
def insertWidget(self, index, w):
|
51
|
+
self.insertItem(index, QWidgetItem(w))
|
52
|
+
self.addChildWidget(w)
|
53
|
+
self._onWidgetAdded(w, index)
|
54
|
+
|
55
|
+
def _onWidgetAdded(self, w, index=-1):
|
56
|
+
if not self._isInstalledEventFilter:
|
57
|
+
if w.parent():
|
58
|
+
self._wParent = w.parent()
|
59
|
+
w.parent().installEventFilter(self)
|
60
|
+
else:
|
61
|
+
w.installEventFilter(self)
|
62
|
+
|
63
|
+
if not self.needAni:
|
64
|
+
return
|
65
|
+
|
66
|
+
ani = QPropertyAnimation(w, b'geometry')
|
67
|
+
ani.setEndValue(QRect(QPoint(0, 0), w.size()))
|
68
|
+
ani.setDuration(self.duration)
|
69
|
+
ani.setEasingCurve(self.ease)
|
70
|
+
w.setProperty('flowAni', ani)
|
71
|
+
self._aniGroup.addAnimation(ani)
|
72
|
+
|
73
|
+
if index == -1:
|
74
|
+
self._anis.append(ani)
|
75
|
+
else:
|
76
|
+
self._anis.insert(index, ani)
|
77
|
+
|
78
|
+
def setAnimation(self, duration, ease=QEasingCurve.Linear):
|
79
|
+
""" set the moving animation
|
80
|
+
|
81
|
+
Parameters
|
82
|
+
----------
|
83
|
+
duration: int
|
84
|
+
the duration of animation in milliseconds
|
85
|
+
|
86
|
+
ease: QEasingCurve
|
87
|
+
the easing curve of animation
|
88
|
+
"""
|
89
|
+
if not self.needAni:
|
90
|
+
return
|
91
|
+
|
92
|
+
self.duration = duration
|
93
|
+
self.ease = ease
|
94
|
+
|
95
|
+
for ani in self._anis:
|
96
|
+
ani.setDuration(duration)
|
97
|
+
ani.setEasingCurve(ease)
|
98
|
+
|
99
|
+
def count(self):
|
100
|
+
return len(self._items)
|
101
|
+
|
102
|
+
def itemAt(self, index: int):
|
103
|
+
if 0 <= index < len(self._items):
|
104
|
+
return self._items[index]
|
105
|
+
|
106
|
+
return None
|
107
|
+
|
108
|
+
def takeAt(self, index: int):
|
109
|
+
if 0 <= index < len(self._items):
|
110
|
+
item = self._items[index] # type: QLayoutItem
|
111
|
+
ani = item.widget().property('flowAni')
|
112
|
+
if ani:
|
113
|
+
self._anis.remove(ani)
|
114
|
+
self._aniGroup.removeAnimation(ani)
|
115
|
+
ani.deleteLater()
|
116
|
+
|
117
|
+
return self._items.pop(index).widget()
|
118
|
+
|
119
|
+
return None
|
120
|
+
|
121
|
+
def removeWidget(self, widget):
|
122
|
+
for i, item in enumerate(self._items):
|
123
|
+
if item.widget() is widget:
|
124
|
+
return self.takeAt(i)
|
125
|
+
|
126
|
+
def removeAllWidgets(self):
|
127
|
+
""" remove all widgets from layout """
|
128
|
+
while self._items:
|
129
|
+
self.takeAt(0)
|
130
|
+
|
131
|
+
def takeAllWidgets(self):
|
132
|
+
""" remove all widgets from layout and delete them """
|
133
|
+
while self._items:
|
134
|
+
w = self.takeAt(0)
|
135
|
+
if w:
|
136
|
+
w.deleteLater()
|
137
|
+
|
138
|
+
def expandingDirections(self):
|
139
|
+
return Qt.Orientation(0)
|
140
|
+
|
141
|
+
def hasHeightForWidth(self):
|
142
|
+
return True
|
143
|
+
|
144
|
+
def heightForWidth(self, width: int):
|
145
|
+
""" get the minimal height according to width """
|
146
|
+
return self._doLayout(QRect(0, 0, width, 0), False)
|
147
|
+
|
148
|
+
def setGeometry(self, rect: QRect):
|
149
|
+
super().setGeometry(rect)
|
150
|
+
|
151
|
+
if self.needAni:
|
152
|
+
self._deBounceTimer.start(80)
|
153
|
+
else:
|
154
|
+
self._doLayout(rect, True)
|
155
|
+
|
156
|
+
def sizeHint(self):
|
157
|
+
return self.minimumSize()
|
158
|
+
|
159
|
+
def minimumSize(self):
|
160
|
+
size = QSize()
|
161
|
+
|
162
|
+
for item in self._items:
|
163
|
+
size = size.expandedTo(item.minimumSize())
|
164
|
+
|
165
|
+
m = self.contentsMargins()
|
166
|
+
size += QSize(m.left()+m.right(), m.top()+m.bottom())
|
167
|
+
|
168
|
+
return size
|
169
|
+
|
170
|
+
def setVerticalSpacing(self, spacing: int):
|
171
|
+
""" set vertical spacing between widgets """
|
172
|
+
self._verticalSpacing = spacing
|
173
|
+
|
174
|
+
def verticalSpacing(self):
|
175
|
+
""" get vertical spacing between widgets """
|
176
|
+
return self._verticalSpacing
|
177
|
+
|
178
|
+
def setHorizontalSpacing(self, spacing: int):
|
179
|
+
""" set horizontal spacing between widgets """
|
180
|
+
self._horizontalSpacing = spacing
|
181
|
+
|
182
|
+
def horizontalSpacing(self):
|
183
|
+
""" get horizontal spacing between widgets """
|
184
|
+
return self._horizontalSpacing
|
185
|
+
|
186
|
+
def eventFilter(self, obj: QObject, event: QEvent) -> bool:
|
187
|
+
if obj in [w.widget() for w in self._items] and event.type() == QEvent.Type.ParentChange:
|
188
|
+
self._wParent = obj.parent()
|
189
|
+
obj.parent().installEventFilter(self)
|
190
|
+
self._isInstalledEventFilter = True
|
191
|
+
|
192
|
+
if obj == self._wParent and event.type() == QEvent.Type.Show:
|
193
|
+
self._doLayout(self.geometry(), True)
|
194
|
+
self._isInstalledEventFilter = True
|
195
|
+
|
196
|
+
return super().eventFilter(obj, event)
|
197
|
+
|
198
|
+
def _doLayout(self, rect: QRect, move: bool):
|
199
|
+
""" adjust widgets position according to the window size """
|
200
|
+
aniRestart = False
|
201
|
+
margin = self.contentsMargins()
|
202
|
+
x = rect.x() + margin.left()
|
203
|
+
y = rect.y() + margin.top()
|
204
|
+
rowHeight = 0
|
205
|
+
spaceX = self.horizontalSpacing()
|
206
|
+
spaceY = self.verticalSpacing()
|
207
|
+
|
208
|
+
for i, item in enumerate(self._items):
|
209
|
+
if item.widget() and not item.widget().isVisible() and self.isTight:
|
210
|
+
continue
|
211
|
+
|
212
|
+
nextX = x + item.sizeHint().width() + spaceX
|
213
|
+
|
214
|
+
if nextX - spaceX > rect.right() - margin.right() and rowHeight > 0:
|
215
|
+
x = rect.x() + margin.left()
|
216
|
+
y = y + rowHeight + spaceY
|
217
|
+
nextX = x + item.sizeHint().width() + spaceX
|
218
|
+
rowHeight = 0
|
219
|
+
|
220
|
+
if move:
|
221
|
+
target = QRect(QPoint(x, y), item.sizeHint())
|
222
|
+
if not self.needAni:
|
223
|
+
item.setGeometry(target)
|
224
|
+
elif target != self._anis[i].endValue():
|
225
|
+
self._anis[i].stop()
|
226
|
+
self._anis[i].setEndValue(target)
|
227
|
+
aniRestart = True
|
228
|
+
|
229
|
+
x = nextX
|
230
|
+
rowHeight = max(rowHeight, item.sizeHint().height())
|
231
|
+
|
232
|
+
if self.needAni and aniRestart:
|
233
|
+
self._aniGroup.stop()
|
234
|
+
self._aniGroup.start()
|
235
|
+
|
236
|
+
return y + rowHeight + margin.bottom() - rect.y()
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
from typing import List
|
3
|
+
from PySide6.QtCore import Qt
|
4
|
+
from PySide6.QtWidgets import QVBoxLayout, QWidget
|
5
|
+
|
6
|
+
|
7
|
+
class VBoxLayout(QVBoxLayout):
|
8
|
+
""" Vertical box layout """
|
9
|
+
|
10
|
+
def __init__(self, parent):
|
11
|
+
super().__init__(parent)
|
12
|
+
self.widgets = []
|
13
|
+
|
14
|
+
def addWidgets(self, widgets: List[QWidget], stretch=0, alignment=Qt.AlignTop):
|
15
|
+
""" add widgets to layout """
|
16
|
+
for widget in widgets:
|
17
|
+
self.addWidget(widget, stretch, alignment)
|
18
|
+
|
19
|
+
def addWidget(self, widget: QWidget, stretch=0, alignment=Qt.AlignTop):
|
20
|
+
""" add widget to layout """
|
21
|
+
super().addWidget(widget, stretch, alignment)
|
22
|
+
self.widgets.append(widget)
|
23
|
+
widget.show()
|
24
|
+
|
25
|
+
def removeWidget(self, widget: QWidget):
|
26
|
+
""" remove widget from layout but not delete it """
|
27
|
+
super().removeWidget(widget)
|
28
|
+
self.widgets.remove(widget)
|
29
|
+
|
30
|
+
def deleteWidget(self, widget: QWidget):
|
31
|
+
""" remove widget from layout and delete it """
|
32
|
+
self.removeWidget(widget)
|
33
|
+
widget.hide()
|
34
|
+
widget.deleteLater()
|
35
|
+
|
36
|
+
def removeAllWidget(self):
|
37
|
+
""" remove all widgets from layout """
|
38
|
+
for widget in self.widgets:
|
39
|
+
super().removeWidget(widget)
|
40
|
+
|
41
|
+
self.widgets.clear()
|
@@ -0,0 +1,6 @@
|
|
1
|
+
from .acrylic_menu import AcrylicMenu, AcrylicLineEditMenu, AcrylicCheckableMenu, AcrylicCheckableSystemTrayMenu, AcrylicSystemTrayMenu
|
2
|
+
from .acrylic_line_edit import AcrylicLineEditBase, AcrylicLineEdit, AcrylicSearchLineEdit
|
3
|
+
from .acrylic_combo_box import AcrylicComboBox, AcrylicComboBoxSettingCard, AcrylicEditableComboBox
|
4
|
+
from .acrylic_widget import AcrylicWidget, AcrylicBrush
|
5
|
+
from .acrylic_flyout import AcrylicFlyoutView, AcrylicFlyoutViewBase, AcrylicFlyout
|
6
|
+
from .acrylic_tool_tip import AcrylicToolTip, AcrylicToolTipFilter
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
from PySide6.QtCore import Qt, QPoint
|
3
|
+
from PySide6.QtGui import QAction
|
4
|
+
|
5
|
+
|
6
|
+
from .acrylic_menu import AcrylicMenuBase, AcrylicMenuActionListWidget
|
7
|
+
from .acrylic_line_edit import AcrylicLineEditBase
|
8
|
+
from ..widgets.combo_box import ComboBoxMenu, ComboBox, EditableComboBox
|
9
|
+
from ..widgets.menu import MenuAnimationType, RoundMenu, IndicatorMenuItemDelegate
|
10
|
+
from ..settings import SettingCard
|
11
|
+
from ...common.config import OptionsConfigItem, qconfig
|
12
|
+
|
13
|
+
|
14
|
+
class AcrylicComboMenuActionListWidget(AcrylicMenuActionListWidget):
|
15
|
+
|
16
|
+
def _topMargin(self):
|
17
|
+
return 2
|
18
|
+
|
19
|
+
|
20
|
+
class AcrylicComboBoxMenu(AcrylicMenuBase, RoundMenu):
|
21
|
+
|
22
|
+
def __init__(self, parent=None):
|
23
|
+
super().__init__(parent=parent)
|
24
|
+
self.setUpMenu(AcrylicComboMenuActionListWidget(self))
|
25
|
+
|
26
|
+
self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
27
|
+
self.view.setItemDelegate(IndicatorMenuItemDelegate())
|
28
|
+
self.view.setObjectName('comboListWidget')
|
29
|
+
self.setItemHeight(33)
|
30
|
+
|
31
|
+
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
32
|
+
return super().exec(pos, ani, aniType)
|
33
|
+
|
34
|
+
|
35
|
+
class AcrylicComboBox(ComboBox):
|
36
|
+
""" Acrylic combo box """
|
37
|
+
|
38
|
+
def _createComboMenu(self):
|
39
|
+
return AcrylicComboBoxMenu(self)
|
40
|
+
|
41
|
+
|
42
|
+
class AcrylicEditableComboBox(AcrylicLineEditBase, EditableComboBox):
|
43
|
+
""" Acrylic combo box """
|
44
|
+
|
45
|
+
def _createComboMenu(self):
|
46
|
+
return AcrylicComboBoxMenu(self)
|
47
|
+
|
48
|
+
|
49
|
+
class AcrylicComboBoxSettingCard(SettingCard):
|
50
|
+
""" Setting card with a combo box """
|
51
|
+
|
52
|
+
def __init__(self, configItem: OptionsConfigItem, icon, title, content=None, texts=None, parent=None):
|
53
|
+
"""
|
54
|
+
Parameters
|
55
|
+
----------
|
56
|
+
configItem: OptionsConfigItem
|
57
|
+
configuration item operated by the card
|
58
|
+
|
59
|
+
icon: str | QIcon | FluentIconBase
|
60
|
+
the icon to be drawn
|
61
|
+
|
62
|
+
title: str
|
63
|
+
the title of card
|
64
|
+
|
65
|
+
content: str
|
66
|
+
the content of card
|
67
|
+
|
68
|
+
texts: List[str]
|
69
|
+
the text of items
|
70
|
+
|
71
|
+
parent: QWidget
|
72
|
+
parent widget
|
73
|
+
"""
|
74
|
+
super().__init__(icon, title, content, parent)
|
75
|
+
self.configItem = configItem
|
76
|
+
self.comboBox = AcrylicComboBox(self)
|
77
|
+
self.hBoxLayout.addWidget(self.comboBox, 0, Qt.AlignRight)
|
78
|
+
self.hBoxLayout.addSpacing(16)
|
79
|
+
|
80
|
+
self.optionToText = {o: t for o, t in zip(configItem.options, texts)}
|
81
|
+
for text, option in zip(texts, configItem.options):
|
82
|
+
self.comboBox.addItem(text, userData=option)
|
83
|
+
|
84
|
+
self.comboBox.setCurrentText(self.optionToText[qconfig.get(configItem)])
|
85
|
+
self.comboBox.currentIndexChanged.connect(self._onCurrentIndexChanged)
|
86
|
+
configItem.valueChanged.connect(self.setValue)
|
87
|
+
|
88
|
+
def _onCurrentIndexChanged(self, index: int):
|
89
|
+
qconfig.set(self.configItem, self.comboBox.itemData(index))
|
90
|
+
|
91
|
+
def setValue(self, value):
|
92
|
+
if value not in self.optionToText:
|
93
|
+
return
|
94
|
+
|
95
|
+
self.comboBox.setCurrentText(self.optionToText[value])
|
96
|
+
qconfig.set(self.configItem, value)
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
from typing import Union
|
3
|
+
from PySide6.QtCore import QPoint, Qt, QRect, QRectF
|
4
|
+
from PySide6.QtGui import QPixmap, QPainter, QColor, QPainterPath, QIcon, QImage
|
5
|
+
from PySide6.QtWidgets import QWidget
|
6
|
+
|
7
|
+
from ...common.style_sheet import isDarkTheme
|
8
|
+
from ...common.icon import FluentIconBase
|
9
|
+
from ..widgets.flyout import FlyoutAnimationType, FlyoutViewBase, FlyoutView, Flyout, FlyoutAnimationManager
|
10
|
+
from .acrylic_widget import AcrylicWidget
|
11
|
+
|
12
|
+
|
13
|
+
class AcrylicFlyoutViewBase(AcrylicWidget, FlyoutViewBase):
|
14
|
+
""" Acrylic flyout view base """
|
15
|
+
|
16
|
+
def acrylicClipPath(self):
|
17
|
+
path = QPainterPath()
|
18
|
+
path.addRoundedRect(QRectF(self.rect().adjusted(1, 1, -1, -1)), 8, 8)
|
19
|
+
return path
|
20
|
+
|
21
|
+
def paintEvent(self, e):
|
22
|
+
painter = QPainter(self)
|
23
|
+
painter.setRenderHints(QPainter.Antialiasing)
|
24
|
+
self._drawAcrylic(painter)
|
25
|
+
|
26
|
+
# draw border
|
27
|
+
painter.setBrush(Qt.NoBrush)
|
28
|
+
painter.setPen(self.borderColor())
|
29
|
+
rect = QRectF(self.rect()).adjusted(1, 1, -1, -1)
|
30
|
+
painter.drawRoundedRect(rect, 8, 8)
|
31
|
+
|
32
|
+
|
33
|
+
class AcrylicFlyoutView(AcrylicWidget, FlyoutView):
|
34
|
+
""" Acrylic flyout view """
|
35
|
+
|
36
|
+
def acrylicClipPath(self):
|
37
|
+
path = QPainterPath()
|
38
|
+
path.addRoundedRect(QRectF(self.rect().adjusted(1, 1, -1, -1)), 8, 8)
|
39
|
+
return path
|
40
|
+
|
41
|
+
def paintEvent(self, e):
|
42
|
+
painter = QPainter(self)
|
43
|
+
painter.setRenderHints(QPainter.Antialiasing)
|
44
|
+
self._drawAcrylic(painter)
|
45
|
+
|
46
|
+
# draw border
|
47
|
+
painter.setBrush(Qt.NoBrush)
|
48
|
+
painter.setPen(self.borderColor())
|
49
|
+
rect = self.rect().adjusted(1, 1, -1, -1)
|
50
|
+
painter.drawRoundedRect(rect, 8, 8)
|
51
|
+
|
52
|
+
|
53
|
+
class AcrylicFlyout(Flyout):
|
54
|
+
""" Acrylic flyout """
|
55
|
+
|
56
|
+
@classmethod
|
57
|
+
def create(cls, title: str, content: str, icon: Union[FluentIconBase, QIcon, str] = None,
|
58
|
+
image: Union[str, QPixmap, QImage] = None, isClosable=False, target: Union[QWidget, QPoint] = None,
|
59
|
+
parent=None, aniType=FlyoutAnimationType.PULL_UP, isDeleteOnClose=True):
|
60
|
+
""" create and show a flyout using the default view
|
61
|
+
|
62
|
+
Parameters
|
63
|
+
----------
|
64
|
+
title: str
|
65
|
+
the title of teaching tip
|
66
|
+
|
67
|
+
content: str
|
68
|
+
the content of teaching tip
|
69
|
+
|
70
|
+
icon: InfoBarIcon | FluentIconBase | QIcon | str
|
71
|
+
the icon of teaching tip
|
72
|
+
|
73
|
+
image: str | QPixmap | QImage
|
74
|
+
the image of teaching tip
|
75
|
+
|
76
|
+
isClosable: bool
|
77
|
+
whether to show the close button
|
78
|
+
|
79
|
+
target: QWidget | QPoint
|
80
|
+
the target widget or position to show flyout
|
81
|
+
|
82
|
+
parent: QWidget
|
83
|
+
parent window
|
84
|
+
|
85
|
+
aniType: FlyoutAnimationType
|
86
|
+
flyout animation type
|
87
|
+
|
88
|
+
isDeleteOnClose: bool
|
89
|
+
whether delete flyout automatically when flyout is closed
|
90
|
+
"""
|
91
|
+
view = AcrylicFlyoutView(title, content, icon, image, isClosable)
|
92
|
+
w = cls.make(view, target, parent, aniType, isDeleteOnClose)
|
93
|
+
view.closed.connect(w.close)
|
94
|
+
return w
|
95
|
+
|
96
|
+
def exec(self, pos: QPoint, aniType=FlyoutAnimationType.PULL_UP):
|
97
|
+
""" show calendar view """
|
98
|
+
self.aniManager = FlyoutAnimationManager.make(aniType, self)
|
99
|
+
|
100
|
+
if isinstance(self.view, AcrylicWidget):
|
101
|
+
pos = self.aniManager._adjustPosition(pos)
|
102
|
+
self.view.acrylicBrush.grabImage(QRect(pos, self.layout().sizeHint()))
|
103
|
+
|
104
|
+
self.show()
|
105
|
+
self.aniManager.exec(pos)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
from .acrylic_menu import AcrylicCompleterMenu, AcrylicLineEditMenu
|
3
|
+
from ..widgets.line_edit import LineEdit, SearchLineEdit
|
4
|
+
|
5
|
+
|
6
|
+
class AcrylicLineEditBase:
|
7
|
+
""" Acrylic line edit base """
|
8
|
+
|
9
|
+
def __init__(self, *args, **kwargs) -> None:
|
10
|
+
super().__init__(*args, **kwargs)
|
11
|
+
|
12
|
+
def setCompleter(self, completer):
|
13
|
+
super().setCompleter(completer)
|
14
|
+
self.setCompleterMenu(AcrylicCompleterMenu(self))
|
15
|
+
|
16
|
+
def contextMenuEvent(self, e):
|
17
|
+
menu = AcrylicLineEditMenu(self)
|
18
|
+
menu.exec(e.globalPos())
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
class AcrylicLineEdit(AcrylicLineEditBase, LineEdit):
|
23
|
+
""" Acrylic line edit """
|
24
|
+
|
25
|
+
|
26
|
+
class AcrylicSearchLineEdit(AcrylicLineEditBase, SearchLineEdit):
|
27
|
+
""" Acrylic search line edit """
|