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,413 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
from typing import Union
|
3
|
+
import sys
|
4
|
+
|
5
|
+
from PySide6.QtCore import Qt, QSize, QRect
|
6
|
+
from PySide6.QtGui import QIcon, QPainter, QColor
|
7
|
+
from PySide6.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QLabel, QApplication
|
8
|
+
|
9
|
+
from ..common.config import qconfig
|
10
|
+
from ..common.icon import FluentIconBase
|
11
|
+
from ..common.router import qrouter
|
12
|
+
from ..common.style_sheet import FluentStyleSheet, isDarkTheme, setTheme, Theme
|
13
|
+
from ..common.animation import BackgroundAnimationWidget
|
14
|
+
from ..components.widgets.frameless_window import FramelessWindow
|
15
|
+
from ..components.navigation import (NavigationInterface, NavigationBar, NavigationItemPosition,
|
16
|
+
NavigationBarPushButton, NavigationTreeWidget)
|
17
|
+
from .stacked_widget import StackedWidget
|
18
|
+
|
19
|
+
from fframelesswindow import TitleBar, TitleBarBase
|
20
|
+
|
21
|
+
|
22
|
+
class FluentWindowBase(BackgroundAnimationWidget, FramelessWindow):
|
23
|
+
""" Fluent window base class """
|
24
|
+
|
25
|
+
def __init__(self, parent=None):
|
26
|
+
self._isMicaEnabled = False
|
27
|
+
self._lightBackgroundColor = QColor(240, 244, 249)
|
28
|
+
self._darkBackgroundColor = QColor(32, 32, 32)
|
29
|
+
super().__init__(parent=parent)
|
30
|
+
|
31
|
+
self.hBoxLayout = QHBoxLayout(self)
|
32
|
+
self.stackedWidget = StackedWidget(self)
|
33
|
+
self.navigationInterface = None
|
34
|
+
|
35
|
+
# initialize layout
|
36
|
+
self.hBoxLayout.setSpacing(0)
|
37
|
+
self.hBoxLayout.setContentsMargins(0, 0, 0, 0)
|
38
|
+
|
39
|
+
FluentStyleSheet.FLUENT_WINDOW.apply(self.stackedWidget)
|
40
|
+
|
41
|
+
# enable mica effect on win11
|
42
|
+
self.setMicaEffectEnabled(True)
|
43
|
+
|
44
|
+
# show system title bar buttons on macOS
|
45
|
+
if sys.platform == "darwin":
|
46
|
+
self.setSystemTitleBarButtonVisible(True)
|
47
|
+
|
48
|
+
qconfig.themeChangedFinished.connect(self._onThemeChangedFinished)
|
49
|
+
|
50
|
+
def addSubInterface(self, interface: QWidget, icon: Union[FluentIconBase, QIcon, str], text: str,
|
51
|
+
position=NavigationItemPosition.TOP):
|
52
|
+
""" add sub interface """
|
53
|
+
raise NotImplementedError
|
54
|
+
|
55
|
+
def removeInterface(self, interface: QWidget, isDelete=False):
|
56
|
+
""" remove sub interface
|
57
|
+
|
58
|
+
Parameters
|
59
|
+
----------
|
60
|
+
interface: QWidget
|
61
|
+
sub interface to be removed
|
62
|
+
|
63
|
+
isDelete: bool
|
64
|
+
whether to delete the sub interface
|
65
|
+
"""
|
66
|
+
raise NotImplementedError
|
67
|
+
|
68
|
+
def switchTo(self, interface: QWidget):
|
69
|
+
self.stackedWidget.setCurrentWidget(interface, popOut=False)
|
70
|
+
|
71
|
+
def _onCurrentInterfaceChanged(self, index: int):
|
72
|
+
widget = self.stackedWidget.widget(index)
|
73
|
+
self.navigationInterface.setCurrentItem(widget.objectName())
|
74
|
+
qrouter.push(self.stackedWidget, widget.objectName())
|
75
|
+
|
76
|
+
self._updateStackedBackground()
|
77
|
+
|
78
|
+
def _updateStackedBackground(self):
|
79
|
+
isTransparent = self.stackedWidget.currentWidget().property("isStackedTransparent")
|
80
|
+
if bool(self.stackedWidget.property("isTransparent")) == isTransparent:
|
81
|
+
return
|
82
|
+
|
83
|
+
self.stackedWidget.setProperty("isTransparent", isTransparent)
|
84
|
+
self.stackedWidget.setStyle(QApplication.style())
|
85
|
+
|
86
|
+
def setCustomBackgroundColor(self, light, dark):
|
87
|
+
""" set custom background color
|
88
|
+
|
89
|
+
Parameters
|
90
|
+
----------
|
91
|
+
light, dark: QColor | Qt.GlobalColor | str
|
92
|
+
background color in light/dark theme mode
|
93
|
+
"""
|
94
|
+
self._lightBackgroundColor = QColor(light)
|
95
|
+
self._darkBackgroundColor = QColor(dark)
|
96
|
+
self._updateBackgroundColor()
|
97
|
+
|
98
|
+
def _normalBackgroundColor(self):
|
99
|
+
if not self.isMicaEffectEnabled():
|
100
|
+
return self._darkBackgroundColor if isDarkTheme() else self._lightBackgroundColor
|
101
|
+
|
102
|
+
return QColor(0, 0, 0, 0)
|
103
|
+
|
104
|
+
def _onThemeChangedFinished(self):
|
105
|
+
if self.isMicaEffectEnabled():
|
106
|
+
self.windowEffect.setMicaEffect(self.winId(), isDarkTheme())
|
107
|
+
|
108
|
+
def paintEvent(self, e):
|
109
|
+
super().paintEvent(e)
|
110
|
+
painter = QPainter(self)
|
111
|
+
painter.setPen(Qt.NoPen)
|
112
|
+
painter.setBrush(self.backgroundColor)
|
113
|
+
painter.drawRect(self.rect())
|
114
|
+
|
115
|
+
def setMicaEffectEnabled(self, isEnabled: bool):
|
116
|
+
""" set whether the mica effect is enabled, only available on Win11 """
|
117
|
+
if sys.platform != 'win32' or sys.getwindowsversion().build < 22000:
|
118
|
+
return
|
119
|
+
|
120
|
+
self._isMicaEnabled = isEnabled
|
121
|
+
|
122
|
+
if isEnabled:
|
123
|
+
self.windowEffect.setMicaEffect(self.winId(), isDarkTheme())
|
124
|
+
else:
|
125
|
+
self.windowEffect.removeBackgroundEffect(self.winId())
|
126
|
+
|
127
|
+
self.setBackgroundColor(self._normalBackgroundColor())
|
128
|
+
|
129
|
+
def isMicaEffectEnabled(self):
|
130
|
+
return self._isMicaEnabled
|
131
|
+
|
132
|
+
def systemTitleBarRect(self, size: QSize) -> QRect:
|
133
|
+
""" Returns the system title bar rect, only works for macOS
|
134
|
+
|
135
|
+
Parameters
|
136
|
+
----------
|
137
|
+
size: QSize
|
138
|
+
original system title bar rect
|
139
|
+
"""
|
140
|
+
return QRect(size.width() - 75, 0 if self.isFullScreen() else 9, 75, size.height())
|
141
|
+
|
142
|
+
def setTitleBar(self, titleBar):
|
143
|
+
super().setTitleBar(titleBar)
|
144
|
+
|
145
|
+
# hide title bar buttons on macOS
|
146
|
+
if sys.platform == "darwin" and self.isSystemButtonVisible() and isinstance(titleBar, TitleBarBase):
|
147
|
+
titleBar.minBtn.hide()
|
148
|
+
titleBar.maxBtn.hide()
|
149
|
+
titleBar.closeBtn.hide()
|
150
|
+
|
151
|
+
|
152
|
+
class FluentTitleBar(TitleBar):
|
153
|
+
""" Fluent title bar"""
|
154
|
+
|
155
|
+
def __init__(self, parent):
|
156
|
+
super().__init__(parent)
|
157
|
+
self.setFixedHeight(48)
|
158
|
+
self.hBoxLayout.removeWidget(self.minBtn)
|
159
|
+
self.hBoxLayout.removeWidget(self.maxBtn)
|
160
|
+
self.hBoxLayout.removeWidget(self.closeBtn)
|
161
|
+
|
162
|
+
# add window icon
|
163
|
+
self.iconLabel = QLabel(self)
|
164
|
+
self.iconLabel.setFixedSize(18, 18)
|
165
|
+
self.hBoxLayout.insertWidget(0, self.iconLabel, 0, Qt.AlignLeft | Qt.AlignVCenter)
|
166
|
+
self.window().windowIconChanged.connect(self.setIcon)
|
167
|
+
|
168
|
+
# add title label
|
169
|
+
self.titleLabel = QLabel(self)
|
170
|
+
self.hBoxLayout.insertWidget(1, self.titleLabel, 0, Qt.AlignLeft | Qt.AlignVCenter)
|
171
|
+
self.titleLabel.setObjectName('titleLabel')
|
172
|
+
self.window().windowTitleChanged.connect(self.setTitle)
|
173
|
+
|
174
|
+
self.vBoxLayout = QVBoxLayout()
|
175
|
+
self.buttonLayout = QHBoxLayout()
|
176
|
+
self.buttonLayout.setSpacing(0)
|
177
|
+
self.buttonLayout.setContentsMargins(0, 0, 0, 0)
|
178
|
+
self.buttonLayout.setAlignment(Qt.AlignTop)
|
179
|
+
self.buttonLayout.addWidget(self.minBtn)
|
180
|
+
self.buttonLayout.addWidget(self.maxBtn)
|
181
|
+
self.buttonLayout.addWidget(self.closeBtn)
|
182
|
+
self.vBoxLayout.addLayout(self.buttonLayout)
|
183
|
+
self.vBoxLayout.addStretch(1)
|
184
|
+
self.hBoxLayout.addLayout(self.vBoxLayout, 0)
|
185
|
+
|
186
|
+
FluentStyleSheet.FLUENT_WINDOW.apply(self)
|
187
|
+
|
188
|
+
def setTitle(self, title):
|
189
|
+
self.titleLabel.setText(title)
|
190
|
+
self.titleLabel.adjustSize()
|
191
|
+
|
192
|
+
def setIcon(self, icon):
|
193
|
+
self.iconLabel.setPixmap(QIcon(icon).pixmap(18, 18))
|
194
|
+
|
195
|
+
|
196
|
+
class FluentWindow(FluentWindowBase):
|
197
|
+
""" Fluent window """
|
198
|
+
|
199
|
+
def __init__(self, parent=None):
|
200
|
+
super().__init__(parent)
|
201
|
+
self.setTitleBar(FluentTitleBar(self))
|
202
|
+
|
203
|
+
self.navigationInterface = NavigationInterface(self, showReturnButton=True)
|
204
|
+
self.widgetLayout = QHBoxLayout()
|
205
|
+
|
206
|
+
# initialize layout
|
207
|
+
self.hBoxLayout.addWidget(self.navigationInterface)
|
208
|
+
self.hBoxLayout.addLayout(self.widgetLayout)
|
209
|
+
self.hBoxLayout.setStretchFactor(self.widgetLayout, 1)
|
210
|
+
|
211
|
+
self.widgetLayout.addWidget(self.stackedWidget)
|
212
|
+
self.widgetLayout.setContentsMargins(0, 48, 0, 0)
|
213
|
+
|
214
|
+
self.navigationInterface.displayModeChanged.connect(self.titleBar.raise_)
|
215
|
+
self.titleBar.raise_()
|
216
|
+
|
217
|
+
def addSubInterface(self, interface: QWidget, icon: Union[FluentIconBase, QIcon, str], text: str,
|
218
|
+
position=NavigationItemPosition.TOP, parent=None, isTransparent=False) -> NavigationTreeWidget:
|
219
|
+
""" add sub interface, the object name of `interface` should be set already
|
220
|
+
before calling this method
|
221
|
+
|
222
|
+
Parameters
|
223
|
+
----------
|
224
|
+
interface: QWidget
|
225
|
+
the subinterface to be added
|
226
|
+
|
227
|
+
icon: FluentIconBase | QIcon | str
|
228
|
+
the icon of navigation item
|
229
|
+
|
230
|
+
text: str
|
231
|
+
the text of navigation item
|
232
|
+
|
233
|
+
position: NavigationItemPosition
|
234
|
+
the position of navigation item
|
235
|
+
|
236
|
+
parent: QWidget
|
237
|
+
the parent of navigation item
|
238
|
+
|
239
|
+
isTransparent: bool
|
240
|
+
whether to use transparent background
|
241
|
+
"""
|
242
|
+
if not interface.objectName():
|
243
|
+
raise ValueError("The object name of `interface` can't be empty string.")
|
244
|
+
if parent and not parent.objectName():
|
245
|
+
raise ValueError("The object name of `parent` can't be empty string.")
|
246
|
+
|
247
|
+
interface.setProperty("isStackedTransparent", isTransparent)
|
248
|
+
self.stackedWidget.addWidget(interface)
|
249
|
+
|
250
|
+
# add navigation item
|
251
|
+
routeKey = interface.objectName()
|
252
|
+
item = self.navigationInterface.addItem(
|
253
|
+
routeKey=routeKey,
|
254
|
+
icon=icon,
|
255
|
+
text=text,
|
256
|
+
onClick=lambda: self.switchTo(interface),
|
257
|
+
position=position,
|
258
|
+
tooltip=text,
|
259
|
+
parentRouteKey=parent.objectName() if parent else None
|
260
|
+
)
|
261
|
+
|
262
|
+
# initialize selected item
|
263
|
+
if self.stackedWidget.count() == 1:
|
264
|
+
self.stackedWidget.currentChanged.connect(self._onCurrentInterfaceChanged)
|
265
|
+
self.navigationInterface.setCurrentItem(routeKey)
|
266
|
+
qrouter.setDefaultRouteKey(self.stackedWidget, routeKey)
|
267
|
+
|
268
|
+
self._updateStackedBackground()
|
269
|
+
|
270
|
+
return item
|
271
|
+
|
272
|
+
def removeInterface(self, interface, isDelete=False):
|
273
|
+
self.navigationInterface.removeWidget(interface.objectName())
|
274
|
+
self.stackedWidget.removeWidget(interface)
|
275
|
+
interface.hide()
|
276
|
+
|
277
|
+
if isDelete:
|
278
|
+
interface.deleteLater()
|
279
|
+
|
280
|
+
def resizeEvent(self, e):
|
281
|
+
self.titleBar.move(46, 0)
|
282
|
+
self.titleBar.resize(self.width()-46, self.titleBar.height())
|
283
|
+
|
284
|
+
|
285
|
+
class MSFluentTitleBar(FluentTitleBar):
|
286
|
+
|
287
|
+
def __init__(self, parent):
|
288
|
+
super().__init__(parent)
|
289
|
+
self.hBoxLayout.insertSpacing(0, 20)
|
290
|
+
self.hBoxLayout.insertSpacing(2, 2)
|
291
|
+
|
292
|
+
|
293
|
+
class MSFluentWindow(FluentWindowBase):
|
294
|
+
""" Fluent window in Microsoft Store style """
|
295
|
+
|
296
|
+
def __init__(self, parent=None):
|
297
|
+
super().__init__(parent)
|
298
|
+
self.setTitleBar(MSFluentTitleBar(self))
|
299
|
+
|
300
|
+
self.navigationInterface = NavigationBar(self)
|
301
|
+
|
302
|
+
# initialize layout
|
303
|
+
self.hBoxLayout.setContentsMargins(0, 48, 0, 0)
|
304
|
+
self.hBoxLayout.addWidget(self.navigationInterface)
|
305
|
+
self.hBoxLayout.addWidget(self.stackedWidget, 1)
|
306
|
+
|
307
|
+
self.titleBar.raise_()
|
308
|
+
self.titleBar.setAttribute(Qt.WA_StyledBackground)
|
309
|
+
|
310
|
+
def addSubInterface(self, interface: QWidget, icon: Union[FluentIconBase, QIcon, str], text: str,
|
311
|
+
selectedIcon=None, position=NavigationItemPosition.TOP, isTransparent=False) -> NavigationBarPushButton:
|
312
|
+
""" add sub interface, the object name of `interface` should be set already
|
313
|
+
before calling this method
|
314
|
+
|
315
|
+
Parameters
|
316
|
+
----------
|
317
|
+
interface: QWidget
|
318
|
+
the subinterface to be added
|
319
|
+
|
320
|
+
icon: FluentIconBase | QIcon | str
|
321
|
+
the icon of navigation item
|
322
|
+
|
323
|
+
text: str
|
324
|
+
the text of navigation item
|
325
|
+
|
326
|
+
selectedIcon: str | QIcon | FluentIconBase
|
327
|
+
the icon of navigation item in selected state
|
328
|
+
|
329
|
+
position: NavigationItemPosition
|
330
|
+
the position of navigation item
|
331
|
+
"""
|
332
|
+
if not interface.objectName():
|
333
|
+
raise ValueError("The object name of `interface` can't be empty string.")
|
334
|
+
|
335
|
+
interface.setProperty("isStackedTransparent", isTransparent)
|
336
|
+
self.stackedWidget.addWidget(interface)
|
337
|
+
|
338
|
+
# add navigation item
|
339
|
+
routeKey = interface.objectName()
|
340
|
+
item = self.navigationInterface.addItem(
|
341
|
+
routeKey=routeKey,
|
342
|
+
icon=icon,
|
343
|
+
text=text,
|
344
|
+
onClick=lambda: self.switchTo(interface),
|
345
|
+
selectedIcon=selectedIcon,
|
346
|
+
position=position
|
347
|
+
)
|
348
|
+
|
349
|
+
if self.stackedWidget.count() == 1:
|
350
|
+
self.stackedWidget.currentChanged.connect(self._onCurrentInterfaceChanged)
|
351
|
+
self.navigationInterface.setCurrentItem(routeKey)
|
352
|
+
qrouter.setDefaultRouteKey(self.stackedWidget, routeKey)
|
353
|
+
|
354
|
+
self._updateStackedBackground()
|
355
|
+
|
356
|
+
return item
|
357
|
+
|
358
|
+
def removeInterface(self, interface, isDelete=False):
|
359
|
+
self.navigationInterface.removeWidget(interface.objectName())
|
360
|
+
self.stackedWidget.removeWidget(interface)
|
361
|
+
interface.hide()
|
362
|
+
|
363
|
+
if isDelete:
|
364
|
+
interface.deleteLater()
|
365
|
+
|
366
|
+
|
367
|
+
class SplitTitleBar(TitleBar):
|
368
|
+
|
369
|
+
def __init__(self, parent):
|
370
|
+
super().__init__(parent)
|
371
|
+
# add window icon
|
372
|
+
self.iconLabel = QLabel(self)
|
373
|
+
self.iconLabel.setFixedSize(18, 18)
|
374
|
+
self.hBoxLayout.insertSpacing(0, 12)
|
375
|
+
self.hBoxLayout.insertWidget(1, self.iconLabel, 0, Qt.AlignLeft | Qt.AlignBottom)
|
376
|
+
self.window().windowIconChanged.connect(self.setIcon)
|
377
|
+
|
378
|
+
# add title label
|
379
|
+
self.titleLabel = QLabel(self)
|
380
|
+
self.hBoxLayout.insertWidget(2, self.titleLabel, 0, Qt.AlignLeft | Qt.AlignBottom)
|
381
|
+
self.titleLabel.setObjectName('titleLabel')
|
382
|
+
self.window().windowTitleChanged.connect(self.setTitle)
|
383
|
+
|
384
|
+
FluentStyleSheet.FLUENT_WINDOW.apply(self)
|
385
|
+
|
386
|
+
def setTitle(self, title):
|
387
|
+
self.titleLabel.setText(title)
|
388
|
+
self.titleLabel.adjustSize()
|
389
|
+
|
390
|
+
def setIcon(self, icon):
|
391
|
+
self.iconLabel.setPixmap(QIcon(icon).pixmap(18, 18))
|
392
|
+
|
393
|
+
|
394
|
+
class SplitFluentWindow(FluentWindow):
|
395
|
+
""" Fluent window with split style """
|
396
|
+
|
397
|
+
def __init__(self, parent=None):
|
398
|
+
super().__init__(parent)
|
399
|
+
self.setTitleBar(SplitTitleBar(self))
|
400
|
+
|
401
|
+
if sys.platform == "darwin":
|
402
|
+
self.titleBar.setFixedHeight(48)
|
403
|
+
|
404
|
+
self.widgetLayout.setContentsMargins(0, 0, 0, 0)
|
405
|
+
|
406
|
+
self.titleBar.raise_()
|
407
|
+
self.navigationInterface.displayModeChanged.connect(self.titleBar.raise_)
|
408
|
+
|
409
|
+
|
410
|
+
class FluentBackgroundTheme:
|
411
|
+
""" Fluent background theme """
|
412
|
+
DEFAULT = (QColor(243, 243, 243), QColor(32, 32, 32)) # light, dark
|
413
|
+
DEFAULT_BLUE = (QColor(240, 244, 249), QColor(25, 33, 42))
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
from typing import Union
|
3
|
+
import sys
|
4
|
+
|
5
|
+
from PySide6.QtCore import Qt, QSize, QRectF, QEvent
|
6
|
+
from PySide6.QtGui import QPixmap, QPainter, QColor, QIcon
|
7
|
+
from PySide6.QtWidgets import QWidget, QVBoxLayout, QGraphicsDropShadowEffect
|
8
|
+
|
9
|
+
from ..common.icon import FluentIconBase, drawIcon, toQIcon
|
10
|
+
from ..common.style_sheet import isDarkTheme, FluentStyleSheet
|
11
|
+
from ..components.widgets import IconWidget
|
12
|
+
from fframelesswindow import TitleBar
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
class SplashScreen(QWidget):
|
17
|
+
""" Splash screen """
|
18
|
+
|
19
|
+
def __init__(self, icon: Union[str, QIcon, FluentIconBase], parent=None, enableShadow=True):
|
20
|
+
super().__init__(parent=parent)
|
21
|
+
self._icon = icon
|
22
|
+
self._iconSize = QSize(96, 96)
|
23
|
+
|
24
|
+
self.titleBar = TitleBar(self)
|
25
|
+
self.iconWidget = IconWidget(icon, self)
|
26
|
+
self.shadowEffect = QGraphicsDropShadowEffect(self)
|
27
|
+
|
28
|
+
self.iconWidget.setFixedSize(self._iconSize)
|
29
|
+
self.shadowEffect.setColor(QColor(0, 0, 0, 50))
|
30
|
+
self.shadowEffect.setBlurRadius(15)
|
31
|
+
self.shadowEffect.setOffset(0, 4)
|
32
|
+
|
33
|
+
FluentStyleSheet.FLUENT_WINDOW.apply(self.titleBar)
|
34
|
+
|
35
|
+
if enableShadow:
|
36
|
+
self.iconWidget.setGraphicsEffect(self.shadowEffect)
|
37
|
+
|
38
|
+
if parent:
|
39
|
+
parent.installEventFilter(self)
|
40
|
+
|
41
|
+
if sys.platform == "darwin":
|
42
|
+
self.titleBar.hide()
|
43
|
+
|
44
|
+
def setIcon(self, icon: Union[str, QIcon, FluentIconBase]):
|
45
|
+
self._icon = icon
|
46
|
+
self.update()
|
47
|
+
|
48
|
+
def icon(self):
|
49
|
+
return toQIcon(self._icon)
|
50
|
+
|
51
|
+
def setIconSize(self, size: QSize):
|
52
|
+
self._iconSize = size
|
53
|
+
self.iconWidget.setFixedSize(size)
|
54
|
+
self.update()
|
55
|
+
|
56
|
+
def iconSize(self):
|
57
|
+
return self._iconSize
|
58
|
+
|
59
|
+
def setTitleBar(self, titleBar: QWidget):
|
60
|
+
""" set title bar """
|
61
|
+
self.titleBar.deleteLater()
|
62
|
+
self.titleBar = titleBar
|
63
|
+
titleBar.setParent(self)
|
64
|
+
titleBar.raise_()
|
65
|
+
self.titleBar.resize(self.width(), self.titleBar.height())
|
66
|
+
|
67
|
+
def eventFilter(self, obj, e: QEvent):
|
68
|
+
if obj is self.parent():
|
69
|
+
if e.type() == QEvent.Resize:
|
70
|
+
self.resize(e.size())
|
71
|
+
elif e.type() == QEvent.ChildAdded:
|
72
|
+
self.raise_()
|
73
|
+
|
74
|
+
return super().eventFilter(obj, e)
|
75
|
+
|
76
|
+
def resizeEvent(self, e):
|
77
|
+
iw, ih = self.iconSize().width(), self.iconSize().height()
|
78
|
+
self.iconWidget.move(self.width()//2 - iw//2, self.height()//2 - ih//2)
|
79
|
+
self.titleBar.resize(self.width(), self.titleBar.height())
|
80
|
+
|
81
|
+
def finish(self):
|
82
|
+
""" close splash screen """
|
83
|
+
self.close()
|
84
|
+
|
85
|
+
def paintEvent(self, e):
|
86
|
+
painter = QPainter(self)
|
87
|
+
painter.setPen(Qt.NoPen)
|
88
|
+
|
89
|
+
# draw background
|
90
|
+
c = 32 if isDarkTheme() else 255
|
91
|
+
painter.setBrush(QColor(c, c, c))
|
92
|
+
painter.drawRect(self.rect())
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
from PySide6.QtCore import Qt, Signal, QEasingCurve
|
3
|
+
from PySide6.QtWidgets import QFrame, QHBoxLayout, QAbstractScrollArea
|
4
|
+
|
5
|
+
from ..components.widgets.stacked_widget import PopUpAniStackedWidget
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
class StackedWidget(QFrame):
|
10
|
+
""" Stacked widget """
|
11
|
+
|
12
|
+
currentChanged = Signal(int)
|
13
|
+
|
14
|
+
def __init__(self, parent=None):
|
15
|
+
super().__init__(parent=parent)
|
16
|
+
self.hBoxLayout = QHBoxLayout(self)
|
17
|
+
self.view = PopUpAniStackedWidget(self)
|
18
|
+
|
19
|
+
self.hBoxLayout.setContentsMargins(0, 0, 0, 0)
|
20
|
+
self.hBoxLayout.addWidget(self.view)
|
21
|
+
|
22
|
+
self.view.currentChanged.connect(self.currentChanged)
|
23
|
+
self.setAttribute(Qt.WA_StyledBackground)
|
24
|
+
|
25
|
+
def isAnimationEnabled(self) -> bool:
|
26
|
+
return self.view.isAnimationEnabled
|
27
|
+
|
28
|
+
def setAnimationEnabled(self, isEnabled: bool):
|
29
|
+
"""set whether the pop animation is enabled"""
|
30
|
+
self.view.setAnimationEnabled(isEnabled)
|
31
|
+
|
32
|
+
def addWidget(self, widget):
|
33
|
+
""" add widget to view """
|
34
|
+
self.view.addWidget(widget)
|
35
|
+
|
36
|
+
def removeWidget(self, widget):
|
37
|
+
""" remove widget from view """
|
38
|
+
self.view.removeWidget(widget)
|
39
|
+
|
40
|
+
def widget(self, index: int):
|
41
|
+
return self.view.widget(index)
|
42
|
+
|
43
|
+
def setCurrentWidget(self, widget, popOut=True):
|
44
|
+
if isinstance(widget, QAbstractScrollArea):
|
45
|
+
widget.verticalScrollBar().setValue(0)
|
46
|
+
|
47
|
+
if not popOut:
|
48
|
+
self.view.setCurrentWidget(widget, duration=300)
|
49
|
+
else:
|
50
|
+
self.view.setCurrentWidget(
|
51
|
+
widget, True, False, 200, QEasingCurve.InQuad)
|
52
|
+
|
53
|
+
def setCurrentIndex(self, index, popOut=True):
|
54
|
+
self.setCurrentWidget(self.view.widget(index), popOut)
|
55
|
+
|
56
|
+
def currentIndex(self):
|
57
|
+
return self.view.currentIndex()
|
58
|
+
|
59
|
+
def currentWidget(self):
|
60
|
+
return self.view.currentWidget()
|
61
|
+
|
62
|
+
def indexOf(self, widget):
|
63
|
+
return self.view.indexOf(widget)
|
64
|
+
|
65
|
+
def count(self):
|
66
|
+
return self.view.count()
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: Python-FastUI-Widgets
|
3
|
+
Version: 1.0.0
|
4
|
+
Summary: FastUI on PySide6
|
5
|
+
Author: NumBNN
|
6
|
+
Author-email: NumBNN@outlook.com
|
7
|
+
Keywords: pyside6 fastui widgets
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: Operating System :: OS Independent
|
10
|
+
Description-Content-Type: text/markdown
|
11
|
+
License-File: LICENSE
|
12
|
+
Requires-Dist: PySide6>=6.4.2
|
13
|
+
Requires-Dist: Python-FastUI-Window>=1.0.1
|
14
|
+
Requires-Dist: darkdetect
|
15
|
+
Provides-Extra: full
|
16
|
+
Requires-Dist: scipy; extra == "full"
|
17
|
+
Requires-Dist: pillow; extra == "full"
|
18
|
+
Requires-Dist: colorthief; extra == "full"
|
19
|
+
Dynamic: author
|
20
|
+
Dynamic: author-email
|
21
|
+
Dynamic: classifier
|
22
|
+
Dynamic: description
|
23
|
+
Dynamic: description-content-type
|
24
|
+
Dynamic: keywords
|
25
|
+
Dynamic: license-file
|
26
|
+
Dynamic: provides-extra
|
27
|
+
Dynamic: requires-dist
|
28
|
+
Dynamic: summary
|
29
|
+
|
30
|
+
测试自用
|