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,1059 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
from typing import Union
|
3
|
+
|
4
|
+
from PySide6.QtCore import Signal, QUrl, Qt, QRectF, QSize, QPoint, Property, QRect
|
5
|
+
from PySide6.QtGui import QDesktopServices, QIcon, QPainter, QColor, QPainterPath
|
6
|
+
from PySide6.QtWidgets import QHBoxLayout, QPushButton, QRadioButton, QToolButton, QApplication, QWidget, QSizePolicy
|
7
|
+
|
8
|
+
from ...common.animation import TranslateYAnimation
|
9
|
+
from ...common.icon import FluentIconBase, drawIcon, isDarkTheme, Theme, toQIcon, Icon
|
10
|
+
from ...common.icon import FluentIcon as FIF
|
11
|
+
from ...common.font import setFont, getFont
|
12
|
+
from ...common.style_sheet import FluentStyleSheet, themeColor, ThemeColor
|
13
|
+
from ...common.color import autoFallbackThemeColor
|
14
|
+
from ...common.overload import singledispatchmethod
|
15
|
+
from .menu import RoundMenu, MenuAnimationType
|
16
|
+
|
17
|
+
|
18
|
+
class PushButton(QPushButton):
|
19
|
+
""" Push button
|
20
|
+
|
21
|
+
Constructors
|
22
|
+
------------
|
23
|
+
* PushButton(`parent`: QWidget = None)
|
24
|
+
* PushButton(`text`: str, `parent`: QWidget = None, `icon`: QIcon | str | FluentIconBase = None)
|
25
|
+
* PushButton(`icon`: QIcon | FluentIcon, `text`: str, `parent`: QWidget = None)
|
26
|
+
"""
|
27
|
+
|
28
|
+
@singledispatchmethod
|
29
|
+
def __init__(self, parent: QWidget = None):
|
30
|
+
super().__init__(parent)
|
31
|
+
FluentStyleSheet.BUTTON.apply(self)
|
32
|
+
self.isPressed = False
|
33
|
+
self.isHover = False
|
34
|
+
self.setIconSize(QSize(16, 16))
|
35
|
+
self.setIcon(None)
|
36
|
+
setFont(self)
|
37
|
+
self._postInit()
|
38
|
+
|
39
|
+
@__init__.register
|
40
|
+
def _(self, text: str, parent: QWidget = None, icon: Union[QIcon, str, FluentIconBase] = None):
|
41
|
+
self.__init__(parent=parent)
|
42
|
+
self.setText(text)
|
43
|
+
self.setIcon(icon)
|
44
|
+
|
45
|
+
@__init__.register
|
46
|
+
def _(self, icon: QIcon, text: str, parent: QWidget = None):
|
47
|
+
self.__init__(text, parent, icon)
|
48
|
+
|
49
|
+
@__init__.register
|
50
|
+
def _(self, icon: FluentIconBase, text: str, parent: QWidget = None):
|
51
|
+
self.__init__(text, parent, icon)
|
52
|
+
|
53
|
+
def _postInit(self):
|
54
|
+
pass
|
55
|
+
|
56
|
+
def setIcon(self, icon: Union[QIcon, str, FluentIconBase]):
|
57
|
+
self.setProperty('hasIcon', icon is not None)
|
58
|
+
self.setStyle(QApplication.style())
|
59
|
+
self._icon = icon or QIcon()
|
60
|
+
self.update()
|
61
|
+
|
62
|
+
def icon(self):
|
63
|
+
return toQIcon(self._icon)
|
64
|
+
|
65
|
+
def setProperty(self, name: str, value) -> bool:
|
66
|
+
if name != 'icon':
|
67
|
+
return super().setProperty(name, value)
|
68
|
+
|
69
|
+
self.setIcon(value)
|
70
|
+
return True
|
71
|
+
|
72
|
+
def mousePressEvent(self, e):
|
73
|
+
self.isPressed = True
|
74
|
+
super().mousePressEvent(e)
|
75
|
+
|
76
|
+
def mouseReleaseEvent(self, e):
|
77
|
+
self.isPressed = False
|
78
|
+
super().mouseReleaseEvent(e)
|
79
|
+
|
80
|
+
def enterEvent(self, e):
|
81
|
+
self.isHover = True
|
82
|
+
self.update()
|
83
|
+
|
84
|
+
def leaveEvent(self, e):
|
85
|
+
self.isHover = False
|
86
|
+
self.update()
|
87
|
+
|
88
|
+
def _drawIcon(self, icon, painter, rect, state=QIcon.Off):
|
89
|
+
""" draw icon """
|
90
|
+
drawIcon(icon, painter, rect, state)
|
91
|
+
|
92
|
+
def paintEvent(self, e):
|
93
|
+
super().paintEvent(e)
|
94
|
+
if self.icon().isNull():
|
95
|
+
return
|
96
|
+
|
97
|
+
painter = QPainter(self)
|
98
|
+
painter.setRenderHints(QPainter.Antialiasing |
|
99
|
+
QPainter.SmoothPixmapTransform)
|
100
|
+
|
101
|
+
if not self.isEnabled():
|
102
|
+
painter.setOpacity(0.3628)
|
103
|
+
elif self.isPressed:
|
104
|
+
painter.setOpacity(0.786)
|
105
|
+
|
106
|
+
w, h = self.iconSize().width(), self.iconSize().height()
|
107
|
+
y = (self.height() - h) / 2
|
108
|
+
mw = self.minimumSizeHint().width()
|
109
|
+
if mw > 0:
|
110
|
+
x = 12 + (self.width() - mw) // 2
|
111
|
+
else:
|
112
|
+
x = 12
|
113
|
+
|
114
|
+
if self.isRightToLeft():
|
115
|
+
x = self.width() - w - x
|
116
|
+
|
117
|
+
self._drawIcon(self._icon, painter, QRectF(x, y, w, h))
|
118
|
+
|
119
|
+
|
120
|
+
class PrimaryPushButton(PushButton):
|
121
|
+
""" Primary color push button
|
122
|
+
|
123
|
+
Constructors
|
124
|
+
------------
|
125
|
+
* PrimaryPushButton(`parent`: QWidget = None)
|
126
|
+
* PrimaryPushButton(`text`: str, `parent`: QWidget = None, `icon`: QIcon | str | FluentIconBase = None)
|
127
|
+
* PrimaryPushButton(`icon`: QIcon | FluentIcon, `text`: str, `parent`: QWidget = None)
|
128
|
+
"""
|
129
|
+
|
130
|
+
def _drawIcon(self, icon, painter, rect, state=QIcon.Off):
|
131
|
+
if isinstance(icon, FluentIconBase) and self.isEnabled():
|
132
|
+
# reverse icon color
|
133
|
+
theme = Theme.DARK if not isDarkTheme() else Theme.LIGHT
|
134
|
+
icon = icon.icon(theme)
|
135
|
+
elif not self.isEnabled():
|
136
|
+
painter.setOpacity(0.786 if isDarkTheme() else 0.9)
|
137
|
+
if isinstance(icon, FluentIconBase):
|
138
|
+
icon = icon.icon(Theme.DARK)
|
139
|
+
|
140
|
+
PushButton._drawIcon(self, icon, painter, rect, state)
|
141
|
+
|
142
|
+
|
143
|
+
class TransparentPushButton(PushButton):
|
144
|
+
""" Transparent push button
|
145
|
+
|
146
|
+
Constructors
|
147
|
+
------------
|
148
|
+
* TransparentPushButton(`parent`: QWidget = None)
|
149
|
+
* TransparentPushButton(`text`: str, `parent`: QWidget = None, `icon`: QIcon | str | FluentIconBase = None)
|
150
|
+
* TransparentPushButton(`icon`: QIcon | FluentIcon, `text`: str, `parent`: QWidget = None)
|
151
|
+
"""
|
152
|
+
|
153
|
+
|
154
|
+
class ToggleButton(PushButton):
|
155
|
+
""" Toggle push button
|
156
|
+
|
157
|
+
Constructors
|
158
|
+
------------
|
159
|
+
* ToggleButton(`parent`: QWidget = None)
|
160
|
+
* ToggleButton(`text`: str, `parent`: QWidget = None, `icon`: QIcon | str | FluentIconBase = None)
|
161
|
+
* ToggleButton(`icon`: QIcon | FluentIcon, `text`: str, `parent`: QWidget = None)
|
162
|
+
"""
|
163
|
+
|
164
|
+
def _postInit(self):
|
165
|
+
self.setCheckable(True)
|
166
|
+
self.setChecked(False)
|
167
|
+
|
168
|
+
def _drawIcon(self, icon, painter, rect):
|
169
|
+
if not self.isChecked():
|
170
|
+
return PushButton._drawIcon(self, icon, painter, rect)
|
171
|
+
|
172
|
+
PrimaryPushButton._drawIcon(self, icon, painter, rect, QIcon.On)
|
173
|
+
|
174
|
+
|
175
|
+
TogglePushButton = ToggleButton
|
176
|
+
|
177
|
+
|
178
|
+
class TransparentTogglePushButton(TogglePushButton):
|
179
|
+
""" Transparent toggle push button
|
180
|
+
|
181
|
+
Constructors
|
182
|
+
------------
|
183
|
+
* TransparentTogglePushButton(`parent`: QWidget = None)
|
184
|
+
* TransparentTogglePushButton(`text`: str, `parent`: QWidget = None,
|
185
|
+
`icon`: QIcon | str | FluentIconBase = None)
|
186
|
+
* TransparentTogglePushButton(`icon`: QIcon | FluentIconBase, `text`: str, `parent`: QWidget = None)
|
187
|
+
"""
|
188
|
+
|
189
|
+
|
190
|
+
class HyperlinkButton(PushButton):
|
191
|
+
""" Hyperlink button
|
192
|
+
|
193
|
+
Constructors
|
194
|
+
------------
|
195
|
+
* HyperlinkButton(`parent`: QWidget = None)
|
196
|
+
* HyperlinkButton(`url`: str, `text`: str, `parent`: QWidget = None, `icon`: QIcon | str | FluentIconBase = None)
|
197
|
+
* HyperlinkButton(`icon`: QIcon | FluentIconBase, `url`: str, `text`: str, `parent`: QWidget = None)
|
198
|
+
"""
|
199
|
+
|
200
|
+
@singledispatchmethod
|
201
|
+
def __init__(self, parent: QWidget = None):
|
202
|
+
super().__init__(parent)
|
203
|
+
self._url = QUrl()
|
204
|
+
FluentStyleSheet.BUTTON.apply(self)
|
205
|
+
self.setCursor(Qt.PointingHandCursor)
|
206
|
+
setFont(self)
|
207
|
+
self.clicked.connect(self._onClicked)
|
208
|
+
|
209
|
+
@__init__.register
|
210
|
+
def _(self, url: str, text: str, parent: QWidget = None, icon: Union[QIcon, FluentIconBase, str] = None):
|
211
|
+
self.__init__(parent)
|
212
|
+
self.setText(text)
|
213
|
+
self.url.setUrl(url)
|
214
|
+
self.setIcon(icon)
|
215
|
+
|
216
|
+
@__init__.register
|
217
|
+
def _(self, icon: QIcon, url: str, text: str, parent: QWidget = None):
|
218
|
+
self.__init__(url, text, parent, icon)
|
219
|
+
|
220
|
+
@__init__.register
|
221
|
+
def _(self, icon: FluentIconBase, url: str, text: str, parent: QWidget = None):
|
222
|
+
self.__init__(url, text, parent, icon)
|
223
|
+
|
224
|
+
def getUrl(self):
|
225
|
+
return self._url
|
226
|
+
|
227
|
+
def setUrl(self, url: Union[str, QUrl]):
|
228
|
+
self._url = QUrl(url)
|
229
|
+
|
230
|
+
def _onClicked(self):
|
231
|
+
if self.getUrl().isValid():
|
232
|
+
QDesktopServices.openUrl(self.getUrl())
|
233
|
+
|
234
|
+
def _drawIcon(self, icon, painter, rect, state=QIcon.Off):
|
235
|
+
if isinstance(icon, FluentIconBase) and self.isEnabled():
|
236
|
+
icon = icon.icon(color=themeColor())
|
237
|
+
elif not self.isEnabled():
|
238
|
+
painter.setOpacity(0.3628 if isDarkTheme() else 0.36)
|
239
|
+
|
240
|
+
drawIcon(icon, painter, rect, state)
|
241
|
+
|
242
|
+
url = Property(QUrl, getUrl, setUrl)
|
243
|
+
|
244
|
+
|
245
|
+
class RadioButton(QRadioButton):
|
246
|
+
""" Radio button
|
247
|
+
|
248
|
+
Constructors
|
249
|
+
------------
|
250
|
+
* RadioButton(`parent`: QWidget = None)
|
251
|
+
* RadioButton(`url`: text, `text`: str, `parent`: QWidget = None,
|
252
|
+
`icon`: QIcon | str | FluentIconBase = None)
|
253
|
+
"""
|
254
|
+
|
255
|
+
@singledispatchmethod
|
256
|
+
def __init__(self, parent: QWidget = None):
|
257
|
+
super().__init__(parent)
|
258
|
+
self._lightTextColor = QColor(0, 0, 0)
|
259
|
+
self._darkTextColor = QColor(255, 255, 255)
|
260
|
+
self.lightIndicatorColor = QColor()
|
261
|
+
self.darkIndicatorColor = QColor()
|
262
|
+
self.indicatorPos = QPoint(11, 12)
|
263
|
+
self.isHover = False
|
264
|
+
|
265
|
+
FluentStyleSheet.BUTTON.apply(self)
|
266
|
+
self.setAttribute(Qt.WA_MacShowFocusRect, False)
|
267
|
+
self._postInit()
|
268
|
+
|
269
|
+
@__init__.register
|
270
|
+
def _(self, text: str, parent: QWidget = None):
|
271
|
+
self.__init__(parent)
|
272
|
+
self.setText(text)
|
273
|
+
|
274
|
+
def _postInit(self):
|
275
|
+
pass
|
276
|
+
|
277
|
+
def enterEvent(self, e):
|
278
|
+
self.isHover = True
|
279
|
+
self.update()
|
280
|
+
|
281
|
+
def leaveEvent(self, e):
|
282
|
+
self.isHover = False
|
283
|
+
self.update()
|
284
|
+
|
285
|
+
def paintEvent(self, e):
|
286
|
+
painter = QPainter(self)
|
287
|
+
painter.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing)
|
288
|
+
self._drawIndicator(painter)
|
289
|
+
self._drawText(painter)
|
290
|
+
|
291
|
+
def _drawText(self, painter: QPainter):
|
292
|
+
if not self.isEnabled():
|
293
|
+
painter.setOpacity(0.36)
|
294
|
+
|
295
|
+
painter.setFont(self.font())
|
296
|
+
painter.setPen(self.textColor())
|
297
|
+
painter.drawText(QRect(29, 0, self.width(), self.height()), Qt.AlignVCenter, self.text())
|
298
|
+
|
299
|
+
def _drawIndicator(self, painter: QPainter):
|
300
|
+
if self.isChecked():
|
301
|
+
if self.isEnabled():
|
302
|
+
borderColor = autoFallbackThemeColor(self.lightIndicatorColor, self.darkIndicatorColor)
|
303
|
+
else:
|
304
|
+
borderColor = QColor(255, 255, 255, 40) if isDarkTheme() else QColor(0, 0, 0, 55)
|
305
|
+
|
306
|
+
filledColor = Qt.black if isDarkTheme() else Qt.white
|
307
|
+
|
308
|
+
if self.isHover and not self.isDown():
|
309
|
+
self._drawCircle(painter, self.indicatorPos, 10, 4, borderColor, filledColor)
|
310
|
+
else:
|
311
|
+
self._drawCircle(painter, self.indicatorPos, 10, 5, borderColor, filledColor)
|
312
|
+
|
313
|
+
else:
|
314
|
+
if self.isEnabled():
|
315
|
+
if not self.isDown():
|
316
|
+
borderColor = QColor(255, 255, 255, 153) if isDarkTheme() else QColor(0, 0, 0, 153)
|
317
|
+
else:
|
318
|
+
borderColor = QColor(255, 255, 255, 40) if isDarkTheme() else QColor(0, 0, 0, 55)
|
319
|
+
|
320
|
+
if self.isDown():
|
321
|
+
filledColor = Qt.black if isDarkTheme() else Qt.white
|
322
|
+
elif self.isHover:
|
323
|
+
filledColor = QColor(255, 255, 255, 11) if isDarkTheme() else QColor(0, 0, 0, 15)
|
324
|
+
else:
|
325
|
+
filledColor = QColor(0, 0, 0, 26) if isDarkTheme() else QColor(0, 0, 0, 6)
|
326
|
+
else:
|
327
|
+
filledColor = Qt.transparent
|
328
|
+
borderColor = QColor(255, 255, 255, 40) if isDarkTheme() else QColor(0, 0, 0, 55)
|
329
|
+
|
330
|
+
self._drawCircle(painter, self.indicatorPos, 10, 1, borderColor, filledColor)
|
331
|
+
|
332
|
+
if self.isEnabled() and self.isDown():
|
333
|
+
borderColor = QColor(255, 255, 255, 40) if isDarkTheme() else QColor(0, 0, 0, 24)
|
334
|
+
self._drawCircle(painter, self.indicatorPos, 9, 4, borderColor, Qt.transparent)
|
335
|
+
|
336
|
+
def _drawCircle(self, painter: QPainter, center: QPoint, radius, thickness, borderColor, filledColor):
|
337
|
+
path = QPainterPath()
|
338
|
+
path.setFillRule(Qt.FillRule.WindingFill)
|
339
|
+
|
340
|
+
# outer circle (border)
|
341
|
+
outerRect = QRectF(center.x() - radius, center.y() - radius, 2 * radius, 2 * radius)
|
342
|
+
path.addEllipse(outerRect)
|
343
|
+
|
344
|
+
# inner center (filled)
|
345
|
+
ir = radius - thickness
|
346
|
+
innerRect = QRectF(center.x() - ir, center.y() - ir, 2 * ir, 2 * ir)
|
347
|
+
innerPath = QPainterPath()
|
348
|
+
innerPath.addEllipse(innerRect)
|
349
|
+
|
350
|
+
path = path.subtracted(innerPath)
|
351
|
+
|
352
|
+
# draw outer ring
|
353
|
+
painter.setPen(Qt.NoPen)
|
354
|
+
painter.fillPath(path, borderColor)
|
355
|
+
|
356
|
+
# fill inner circle
|
357
|
+
painter.fillPath(innerPath, filledColor)
|
358
|
+
|
359
|
+
def textColor(self):
|
360
|
+
return self.darkTextColor if isDarkTheme() else self.lightTextColor
|
361
|
+
|
362
|
+
def getLightTextColor(self) -> QColor:
|
363
|
+
return self._lightTextColor
|
364
|
+
|
365
|
+
def getDarkTextColor(self) -> QColor:
|
366
|
+
return self._darkTextColor
|
367
|
+
|
368
|
+
def setLightTextColor(self, color: QColor):
|
369
|
+
self._lightTextColor = QColor(color)
|
370
|
+
self.update()
|
371
|
+
|
372
|
+
def setDarkTextColor(self, color: QColor):
|
373
|
+
self._darkTextColor = QColor(color)
|
374
|
+
self.update()
|
375
|
+
|
376
|
+
def setIndicatorColor(self, light, dark):
|
377
|
+
self.lightIndicatorColor = QColor(light)
|
378
|
+
self.darkIndicatorColor = QColor(dark)
|
379
|
+
self.update()
|
380
|
+
|
381
|
+
def setTextColor(self, light, dark):
|
382
|
+
self.setLightTextColor(light)
|
383
|
+
self.setDarkTextColor(dark)
|
384
|
+
|
385
|
+
lightTextColor = Property(QColor, getLightTextColor, setLightTextColor)
|
386
|
+
darkTextColor = Property(QColor, getDarkTextColor, setDarkTextColor)
|
387
|
+
|
388
|
+
|
389
|
+
class ToolButton(QToolButton):
|
390
|
+
""" Tool button
|
391
|
+
|
392
|
+
Constructors
|
393
|
+
------------
|
394
|
+
* ToolButton(`parent`: QWidget = None)
|
395
|
+
* ToolButton(`icon`: QIcon | str | FluentIconBase, `parent`: QWidget = None)
|
396
|
+
"""
|
397
|
+
|
398
|
+
@singledispatchmethod
|
399
|
+
def __init__(self, parent: QWidget = None):
|
400
|
+
super().__init__(parent)
|
401
|
+
FluentStyleSheet.BUTTON.apply(self)
|
402
|
+
self.isPressed = False
|
403
|
+
self.isHover = False
|
404
|
+
self.setIconSize(QSize(16, 16))
|
405
|
+
self.setIcon(QIcon())
|
406
|
+
setFont(self)
|
407
|
+
self._postInit()
|
408
|
+
|
409
|
+
@__init__.register
|
410
|
+
def _(self, icon: FluentIconBase, parent: QWidget = None):
|
411
|
+
self.__init__(parent)
|
412
|
+
self.setIcon(icon)
|
413
|
+
|
414
|
+
@__init__.register
|
415
|
+
def _(self, icon: QIcon, parent: QWidget = None):
|
416
|
+
self.__init__(parent)
|
417
|
+
self.setIcon(icon)
|
418
|
+
|
419
|
+
@__init__.register
|
420
|
+
def _(self, icon: str, parent: QWidget = None):
|
421
|
+
self.__init__(parent)
|
422
|
+
self.setIcon(icon)
|
423
|
+
|
424
|
+
def _postInit(self):
|
425
|
+
pass
|
426
|
+
|
427
|
+
def setIcon(self, icon: Union[QIcon, str, FluentIconBase]):
|
428
|
+
self._icon = icon
|
429
|
+
self.update()
|
430
|
+
|
431
|
+
def icon(self):
|
432
|
+
return toQIcon(self._icon)
|
433
|
+
|
434
|
+
def setProperty(self, name: str, value) -> bool:
|
435
|
+
if name != 'icon':
|
436
|
+
return super().setProperty(name, value)
|
437
|
+
|
438
|
+
self.setIcon(value)
|
439
|
+
return True
|
440
|
+
|
441
|
+
def mousePressEvent(self, e):
|
442
|
+
self.isPressed = True
|
443
|
+
super().mousePressEvent(e)
|
444
|
+
|
445
|
+
def mouseReleaseEvent(self, e):
|
446
|
+
self.isPressed = False
|
447
|
+
super().mouseReleaseEvent(e)
|
448
|
+
|
449
|
+
def enterEvent(self, e):
|
450
|
+
self.isHover = True
|
451
|
+
self.update()
|
452
|
+
|
453
|
+
def leaveEvent(self, e):
|
454
|
+
self.isHover = False
|
455
|
+
self.update()
|
456
|
+
|
457
|
+
def _drawIcon(self, icon, painter: QPainter, rect: QRectF, state=QIcon.Off):
|
458
|
+
""" draw icon """
|
459
|
+
drawIcon(icon, painter, rect, state)
|
460
|
+
|
461
|
+
def paintEvent(self, e):
|
462
|
+
super().paintEvent(e)
|
463
|
+
if self._icon is None:
|
464
|
+
return
|
465
|
+
|
466
|
+
painter = QPainter(self)
|
467
|
+
painter.setRenderHints(QPainter.Antialiasing |
|
468
|
+
QPainter.SmoothPixmapTransform)
|
469
|
+
|
470
|
+
if not self.isEnabled():
|
471
|
+
painter.setOpacity(0.43)
|
472
|
+
elif self.isPressed:
|
473
|
+
painter.setOpacity(0.63)
|
474
|
+
|
475
|
+
w, h = self.iconSize().width(), self.iconSize().height()
|
476
|
+
y = (self.height() - h) / 2
|
477
|
+
x = (self.width() - w) / 2
|
478
|
+
self._drawIcon(self._icon, painter, QRectF(x, y, w, h))
|
479
|
+
|
480
|
+
|
481
|
+
class TransparentToolButton(ToolButton):
|
482
|
+
""" Transparent background tool button
|
483
|
+
|
484
|
+
Constructors
|
485
|
+
------------
|
486
|
+
* TransparentToolButton(`parent`: QWidget = None)
|
487
|
+
* TransparentToolButton(`icon`: QIcon | str | FluentIconBase, `parent`: QWidget = None)
|
488
|
+
"""
|
489
|
+
|
490
|
+
|
491
|
+
class PrimaryToolButton(ToolButton):
|
492
|
+
""" Primary color tool button
|
493
|
+
|
494
|
+
Constructors
|
495
|
+
------------
|
496
|
+
* PrimaryToolButton(`parent`: QWidget = None)
|
497
|
+
* PrimaryToolButton(`icon`: QIcon | str | FluentIconBase, `parent`: QWidget = None)
|
498
|
+
"""
|
499
|
+
|
500
|
+
def _drawIcon(self, icon, painter: QPainter, rect: QRectF, state=QIcon.Off):
|
501
|
+
if isinstance(icon, FluentIconBase) and self.isEnabled():
|
502
|
+
# reverse icon color
|
503
|
+
theme = Theme.DARK if not isDarkTheme() else Theme.LIGHT
|
504
|
+
icon = icon.icon(theme)
|
505
|
+
elif isinstance(icon, Icon) and self.isEnabled():
|
506
|
+
theme = Theme.DARK if not isDarkTheme() else Theme.LIGHT
|
507
|
+
icon = icon.fluentIcon.icon(theme)
|
508
|
+
elif not self.isEnabled():
|
509
|
+
painter.setOpacity(0.786 if isDarkTheme() else 0.9)
|
510
|
+
if isinstance(icon, FluentIconBase):
|
511
|
+
icon = icon.icon(Theme.DARK)
|
512
|
+
|
513
|
+
return drawIcon(icon, painter, rect, state)
|
514
|
+
|
515
|
+
|
516
|
+
class ToggleToolButton(ToolButton):
|
517
|
+
""" Toggle tool button
|
518
|
+
|
519
|
+
Constructors
|
520
|
+
------------
|
521
|
+
* ToggleToolButton(`parent`: QWidget = None)
|
522
|
+
* ToggleToolButton(`icon`: QIcon | str | FluentIconBase, `parent`: QWidget = None)
|
523
|
+
"""
|
524
|
+
|
525
|
+
def _postInit(self):
|
526
|
+
self.setCheckable(True)
|
527
|
+
self.setChecked(False)
|
528
|
+
|
529
|
+
def _drawIcon(self, icon, painter, rect):
|
530
|
+
if not self.isChecked():
|
531
|
+
return ToolButton._drawIcon(self, icon, painter, rect)
|
532
|
+
|
533
|
+
PrimaryToolButton._drawIcon(self, icon, painter, rect, QIcon.On)
|
534
|
+
|
535
|
+
|
536
|
+
class TransparentToggleToolButton(ToggleToolButton):
|
537
|
+
""" Transparent toggle tool button
|
538
|
+
|
539
|
+
Constructors
|
540
|
+
------------
|
541
|
+
* TransparentToggleToolButton(`parent`: QWidget = None)
|
542
|
+
* TransparentToggleToolButton(`icon`: QIcon | str | FluentIconBase, `parent`: QWidget = None)
|
543
|
+
"""
|
544
|
+
|
545
|
+
|
546
|
+
class DropDownButtonBase:
|
547
|
+
""" Drop down button base class """
|
548
|
+
|
549
|
+
def __init__(self, *args, **kwargs):
|
550
|
+
super().__init__(*args, **kwargs)
|
551
|
+
self._menu = None
|
552
|
+
self.arrowAni = TranslateYAnimation(self)
|
553
|
+
|
554
|
+
def setMenu(self, menu: RoundMenu):
|
555
|
+
self._menu = menu
|
556
|
+
|
557
|
+
def menu(self) -> RoundMenu:
|
558
|
+
return self._menu
|
559
|
+
|
560
|
+
def _showMenu(self):
|
561
|
+
if not self.menu():
|
562
|
+
return
|
563
|
+
|
564
|
+
menu = self.menu()
|
565
|
+
menu.view.setMinimumWidth(self.width())
|
566
|
+
menu.view.adjustSize()
|
567
|
+
menu.adjustSize()
|
568
|
+
|
569
|
+
# determine the animation type by choosing the maximum height of view
|
570
|
+
x = -menu.width()//2 + menu.layout().contentsMargins().left() + self.width()//2
|
571
|
+
pd = self.mapToGlobal(QPoint(x, self.height()))
|
572
|
+
hd = menu.view.heightForAnimation(pd, MenuAnimationType.DROP_DOWN)
|
573
|
+
|
574
|
+
pu = self.mapToGlobal(QPoint(x, 0))
|
575
|
+
hu = menu.view.heightForAnimation(pu, MenuAnimationType.PULL_UP)
|
576
|
+
|
577
|
+
if hd >= hu:
|
578
|
+
menu.view.adjustSize(pd, MenuAnimationType.DROP_DOWN)
|
579
|
+
menu.exec(pd, aniType=MenuAnimationType.DROP_DOWN)
|
580
|
+
else:
|
581
|
+
menu.view.adjustSize(pu, MenuAnimationType.PULL_UP)
|
582
|
+
menu.exec(pu, aniType=MenuAnimationType.PULL_UP)
|
583
|
+
|
584
|
+
def _hideMenu(self):
|
585
|
+
if self.menu():
|
586
|
+
self.menu().hide()
|
587
|
+
|
588
|
+
def _drawDropDownIcon(self, painter, rect):
|
589
|
+
if isDarkTheme():
|
590
|
+
FIF.ARROW_DOWN.render(painter, rect)
|
591
|
+
else:
|
592
|
+
FIF.ARROW_DOWN.render(painter, rect, fill="#646464")
|
593
|
+
|
594
|
+
def paintEvent(self, e):
|
595
|
+
painter = QPainter(self)
|
596
|
+
painter.setRenderHints(QPainter.Antialiasing)
|
597
|
+
if self.isHover:
|
598
|
+
painter.setOpacity(0.8)
|
599
|
+
elif self.isPressed:
|
600
|
+
painter.setOpacity(0.7)
|
601
|
+
|
602
|
+
rect = QRectF(self.width()-22, self.height() /
|
603
|
+
2-5+self.arrowAni.y, 10, 10)
|
604
|
+
self._drawDropDownIcon(painter, rect)
|
605
|
+
|
606
|
+
|
607
|
+
class DropDownPushButton(DropDownButtonBase, PushButton):
|
608
|
+
""" Drop down push button
|
609
|
+
|
610
|
+
Constructors
|
611
|
+
------------
|
612
|
+
* DropDownPushButton(`parent`: QWidget = None)
|
613
|
+
* DropDownPushButton(`text`: str, `parent`: QWidget = None,
|
614
|
+
`icon`: QIcon | str | FluentIconBase = None)
|
615
|
+
* DropDownPushButton(`icon`: QIcon | FluentIcon, `text`: str, `parent`: QWidget = None)
|
616
|
+
"""
|
617
|
+
|
618
|
+
def mouseReleaseEvent(self, e):
|
619
|
+
PushButton.mouseReleaseEvent(self, e)
|
620
|
+
self._showMenu()
|
621
|
+
|
622
|
+
def paintEvent(self, e):
|
623
|
+
PushButton.paintEvent(self, e)
|
624
|
+
DropDownButtonBase.paintEvent(self, e)
|
625
|
+
|
626
|
+
|
627
|
+
class TransparentDropDownPushButton(DropDownPushButton):
|
628
|
+
""" Transparent drop down push button
|
629
|
+
|
630
|
+
Constructors
|
631
|
+
------------
|
632
|
+
* TransparentDropDownPushButton(`parent`: QWidget = None)
|
633
|
+
* TransparentDropDownPushButton(`text`: str, `parent`: QWidget = None,
|
634
|
+
`icon`: QIcon | str | FluentIconBase = None)
|
635
|
+
* TransparentDropDownPushButton(`icon`: QIcon | FluentIcon, `text`: str, `parent`: QWidget = None)
|
636
|
+
"""
|
637
|
+
|
638
|
+
|
639
|
+
class DropDownToolButton(DropDownButtonBase, ToolButton):
|
640
|
+
""" Drop down tool button
|
641
|
+
|
642
|
+
Constructors
|
643
|
+
------------
|
644
|
+
* DropDownToolButton(`parent`: QWidget = None)
|
645
|
+
* DropDownToolButton(`icon`: QIcon | str | FluentIconBase, `parent`: QWidget = None)
|
646
|
+
"""
|
647
|
+
|
648
|
+
def mouseReleaseEvent(self, e):
|
649
|
+
ToolButton.mouseReleaseEvent(self, e)
|
650
|
+
self._showMenu()
|
651
|
+
|
652
|
+
def _drawIcon(self, icon, painter, rect: QRectF):
|
653
|
+
rect.moveLeft(12)
|
654
|
+
return super()._drawIcon(icon, painter, rect)
|
655
|
+
|
656
|
+
def paintEvent(self, e):
|
657
|
+
ToolButton.paintEvent(self, e)
|
658
|
+
DropDownButtonBase.paintEvent(self, e)
|
659
|
+
|
660
|
+
|
661
|
+
class TransparentDropDownToolButton(DropDownToolButton):
|
662
|
+
""" Transparent drop down tool button
|
663
|
+
|
664
|
+
Constructors
|
665
|
+
------------
|
666
|
+
* TransparentDropDownToolButton(`parent`: QWidget = None)
|
667
|
+
* TransparentDropDownToolButton(`icon`: QIcon | str | FluentIconBase, `parent`: QWidget = None)
|
668
|
+
"""
|
669
|
+
|
670
|
+
|
671
|
+
class PrimaryDropDownButtonBase(DropDownButtonBase):
|
672
|
+
""" Primary color drop down button base class """
|
673
|
+
|
674
|
+
def _drawDropDownIcon(self, painter, rect):
|
675
|
+
theme = Theme.DARK if not isDarkTheme() else Theme.LIGHT
|
676
|
+
FIF.ARROW_DOWN.render(painter, rect, theme)
|
677
|
+
|
678
|
+
|
679
|
+
class PrimaryDropDownPushButton(PrimaryDropDownButtonBase, PrimaryPushButton):
|
680
|
+
""" Primary color drop down push button
|
681
|
+
|
682
|
+
Constructors
|
683
|
+
------------
|
684
|
+
* PrimaryDropDownPushButton(`parent`: QWidget = None)
|
685
|
+
* PrimaryDropDownPushButton(`text`: str, `parent`: QWidget = None,
|
686
|
+
`icon`: QIcon | str | FluentIconBase = None)
|
687
|
+
* PrimaryDropDownPushButton(`icon`: QIcon | FluentIcon, `text`: str, `parent`: QWidget = None)
|
688
|
+
"""
|
689
|
+
|
690
|
+
def mouseReleaseEvent(self, e):
|
691
|
+
PrimaryPushButton.mouseReleaseEvent(self, e)
|
692
|
+
self._showMenu()
|
693
|
+
|
694
|
+
def paintEvent(self, e):
|
695
|
+
PrimaryPushButton.paintEvent(self, e)
|
696
|
+
PrimaryDropDownButtonBase.paintEvent(self, e)
|
697
|
+
|
698
|
+
|
699
|
+
class PrimaryDropDownToolButton(PrimaryDropDownButtonBase, PrimaryToolButton):
|
700
|
+
""" Primary drop down tool button
|
701
|
+
|
702
|
+
Constructors
|
703
|
+
------------
|
704
|
+
* PrimaryDropDownToolButton(`parent`: QWidget = None)
|
705
|
+
* PrimaryDropDownToolButton(`icon`: QIcon | str | FluentIconBase, `parent`: QWidget = None)
|
706
|
+
"""
|
707
|
+
|
708
|
+
def mouseReleaseEvent(self, e):
|
709
|
+
PrimaryToolButton.mouseReleaseEvent(self, e)
|
710
|
+
self._showMenu()
|
711
|
+
|
712
|
+
def _drawIcon(self, icon, painter, rect: QRectF):
|
713
|
+
rect.moveLeft(12)
|
714
|
+
return super()._drawIcon(icon, painter, rect)
|
715
|
+
|
716
|
+
def paintEvent(self, e):
|
717
|
+
PrimaryToolButton.paintEvent(self, e)
|
718
|
+
PrimaryDropDownButtonBase.paintEvent(self, e)
|
719
|
+
|
720
|
+
|
721
|
+
class SplitDropButton(ToolButton):
|
722
|
+
|
723
|
+
def _postInit(self):
|
724
|
+
self.arrowAni = TranslateYAnimation(self)
|
725
|
+
self.setIcon(FIF.ARROW_DOWN)
|
726
|
+
self.setIconSize(QSize(10, 10))
|
727
|
+
self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
|
728
|
+
|
729
|
+
def _drawIcon(self, icon, painter, rect):
|
730
|
+
rect.translate(0, self.arrowAni.y)
|
731
|
+
|
732
|
+
if self.isPressed:
|
733
|
+
painter.setOpacity(0.5)
|
734
|
+
elif self.isHover:
|
735
|
+
painter.setOpacity(1)
|
736
|
+
else:
|
737
|
+
painter.setOpacity(0.63)
|
738
|
+
|
739
|
+
super()._drawIcon(icon, painter, rect)
|
740
|
+
|
741
|
+
|
742
|
+
class PrimarySplitDropButton(PrimaryToolButton):
|
743
|
+
|
744
|
+
def _postInit(self):
|
745
|
+
self.arrowAni = TranslateYAnimation(self)
|
746
|
+
self.setIcon(FIF.ARROW_DOWN)
|
747
|
+
self.setIconSize(QSize(10, 10))
|
748
|
+
self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
|
749
|
+
|
750
|
+
def _drawIcon(self, icon, painter, rect):
|
751
|
+
rect.translate(0, self.arrowAni.y)
|
752
|
+
|
753
|
+
if self.isPressed:
|
754
|
+
painter.setOpacity(0.7)
|
755
|
+
elif self.isHover:
|
756
|
+
painter.setOpacity(0.9)
|
757
|
+
else:
|
758
|
+
painter.setOpacity(1)
|
759
|
+
|
760
|
+
if isinstance(icon, FluentIconBase):
|
761
|
+
icon = icon.icon(Theme.DARK if not isDarkTheme() else Theme.LIGHT)
|
762
|
+
|
763
|
+
super()._drawIcon(icon, painter, rect)
|
764
|
+
|
765
|
+
|
766
|
+
class SplitWidgetBase(QWidget):
|
767
|
+
""" Split widget base class """
|
768
|
+
|
769
|
+
dropDownClicked = Signal()
|
770
|
+
|
771
|
+
def __init__(self, parent=None):
|
772
|
+
super().__init__(parent=parent)
|
773
|
+
self.flyout = None # type: QWidget
|
774
|
+
self.dropButton = SplitDropButton(self)
|
775
|
+
|
776
|
+
self.hBoxLayout = QHBoxLayout(self)
|
777
|
+
self.hBoxLayout.setSpacing(0)
|
778
|
+
self.hBoxLayout.setContentsMargins(0, 0, 0, 0)
|
779
|
+
self.hBoxLayout.addWidget(self.dropButton)
|
780
|
+
|
781
|
+
self.dropButton.clicked.connect(self.dropDownClicked)
|
782
|
+
self.dropButton.clicked.connect(self.showFlyout)
|
783
|
+
|
784
|
+
self.setAttribute(Qt.WA_TranslucentBackground)
|
785
|
+
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
786
|
+
|
787
|
+
def setWidget(self, widget: QWidget):
|
788
|
+
""" set the widget on left side """
|
789
|
+
self.hBoxLayout.insertWidget(0, widget, 1, Qt.AlignLeft)
|
790
|
+
|
791
|
+
def setDropButton(self, button):
|
792
|
+
""" set drop dow button """
|
793
|
+
self.hBoxLayout.removeWidget(self.dropButton)
|
794
|
+
self.dropButton.deleteLater()
|
795
|
+
|
796
|
+
self.dropButton = button
|
797
|
+
self.dropButton.clicked.connect(self.dropDownClicked)
|
798
|
+
self.dropButton.clicked.connect(self.showFlyout)
|
799
|
+
self.hBoxLayout.addWidget(button)
|
800
|
+
|
801
|
+
def setDropIcon(self, icon: Union[str, QIcon, FluentIconBase]):
|
802
|
+
""" set the icon of drop down button """
|
803
|
+
self.dropButton.setIcon(icon)
|
804
|
+
self.dropButton.removeEventFilter(self.dropButton.arrowAni)
|
805
|
+
|
806
|
+
def setDropIconSize(self, size: QSize):
|
807
|
+
""" set the icon size of drop down button """
|
808
|
+
self.dropButton.setIconSize(size)
|
809
|
+
|
810
|
+
def setFlyout(self, flyout):
|
811
|
+
""" set the widget pops up when drop down button is clicked
|
812
|
+
|
813
|
+
Parameters
|
814
|
+
----------
|
815
|
+
flyout: QWidget
|
816
|
+
the widget pops up when drop down button is clicked.
|
817
|
+
It should contain `exec(pos: QPoint)` method
|
818
|
+
"""
|
819
|
+
self.flyout = flyout
|
820
|
+
|
821
|
+
def showFlyout(self):
|
822
|
+
""" show flyout """
|
823
|
+
if not self.flyout:
|
824
|
+
return
|
825
|
+
|
826
|
+
w = self.flyout
|
827
|
+
|
828
|
+
if isinstance(w, RoundMenu):
|
829
|
+
w.view.setMinimumWidth(self.width())
|
830
|
+
w.view.adjustSize()
|
831
|
+
w.adjustSize()
|
832
|
+
|
833
|
+
dx = w.layout().contentsMargins().left() if isinstance(w, RoundMenu) else 0
|
834
|
+
x = -w.width()//2 + dx + self.width()//2
|
835
|
+
y = self.height()
|
836
|
+
w.exec(self.mapToGlobal(QPoint(x, y)))
|
837
|
+
|
838
|
+
|
839
|
+
class SplitPushButton(SplitWidgetBase):
|
840
|
+
""" Split push button
|
841
|
+
|
842
|
+
Constructors
|
843
|
+
------------
|
844
|
+
* SplitPushButton(`parent`: QWidget = None)
|
845
|
+
* SplitPushButton(`text`: str, `parent`: QWidget = None, `icon`: QIcon | str | FluentIconBase = None)
|
846
|
+
"""
|
847
|
+
|
848
|
+
clicked = Signal()
|
849
|
+
|
850
|
+
@singledispatchmethod
|
851
|
+
def __init__(self, parent: QWidget = None):
|
852
|
+
super().__init__(parent=parent)
|
853
|
+
self.button = PushButton(self)
|
854
|
+
self.button.setObjectName('splitPushButton')
|
855
|
+
self.button.clicked.connect(self.clicked)
|
856
|
+
self.setWidget(self.button)
|
857
|
+
self._postInit()
|
858
|
+
|
859
|
+
@__init__.register
|
860
|
+
def _(self, text: str, parent: QWidget = None, icon: Union[QIcon, str, FluentIconBase] = None):
|
861
|
+
self.__init__(parent)
|
862
|
+
self.setText(text)
|
863
|
+
self.setIcon(icon)
|
864
|
+
|
865
|
+
@__init__.register
|
866
|
+
def _(self, icon: QIcon, text: str, parent: QWidget = None):
|
867
|
+
self.__init__(text, parent, icon)
|
868
|
+
|
869
|
+
@__init__.register
|
870
|
+
def _(self, icon: FluentIconBase, text: str, parent: QWidget = None):
|
871
|
+
self.__init__(text, parent, icon)
|
872
|
+
|
873
|
+
def _postInit(self):
|
874
|
+
pass
|
875
|
+
|
876
|
+
def text(self):
|
877
|
+
return self.button.text()
|
878
|
+
|
879
|
+
def setText(self, text: str):
|
880
|
+
self.button.setText(text)
|
881
|
+
self.adjustSize()
|
882
|
+
|
883
|
+
def icon(self):
|
884
|
+
return self.button.icon()
|
885
|
+
|
886
|
+
def setIcon(self, icon: Union[QIcon, FluentIconBase, str]):
|
887
|
+
self.button.setIcon(icon)
|
888
|
+
|
889
|
+
def setIconSize(self, size: QSize):
|
890
|
+
self.button.setIconSize(size)
|
891
|
+
|
892
|
+
text_ = Property(str, text, setText)
|
893
|
+
icon_ = Property(QIcon, icon, setIcon)
|
894
|
+
|
895
|
+
|
896
|
+
class PrimarySplitPushButton(SplitPushButton):
|
897
|
+
""" Primary split push button
|
898
|
+
|
899
|
+
Constructors
|
900
|
+
------------
|
901
|
+
* PrimarySplitPushButton(`parent`: QWidget = None)
|
902
|
+
* PrimarySplitPushButton(`text`: str, `parent`: QWidget = None,
|
903
|
+
`icon`: QIcon | str | FluentIconBase = None)
|
904
|
+
* PrimarySplitPushButton(`icon`: QIcon | FluentIcon, `text`: str, `parent`: QWidget = None)
|
905
|
+
"""
|
906
|
+
|
907
|
+
def _postInit(self):
|
908
|
+
self.setDropButton(PrimarySplitDropButton(self))
|
909
|
+
|
910
|
+
self.hBoxLayout.removeWidget(self.button)
|
911
|
+
self.button.deleteLater()
|
912
|
+
|
913
|
+
self.button = PrimaryPushButton(self)
|
914
|
+
self.button.setObjectName('primarySplitPushButton')
|
915
|
+
self.button.clicked.connect(self.clicked)
|
916
|
+
self.setWidget(self.button)
|
917
|
+
|
918
|
+
|
919
|
+
class SplitToolButton(SplitWidgetBase):
|
920
|
+
""" Split tool button
|
921
|
+
|
922
|
+
Constructors
|
923
|
+
------------
|
924
|
+
* SplitToolButton(`parent`: QWidget = None)
|
925
|
+
* SplitToolButton(`icon`: QIcon | str | FluentIconBase, `parent`: QWidget = None)
|
926
|
+
"""
|
927
|
+
|
928
|
+
clicked = Signal()
|
929
|
+
|
930
|
+
@singledispatchmethod
|
931
|
+
def __init__(self, parent: QWidget = None):
|
932
|
+
super().__init__(parent=parent)
|
933
|
+
self.button = ToolButton(self)
|
934
|
+
self.button.setObjectName('splitToolButton')
|
935
|
+
self.button.clicked.connect(self.clicked)
|
936
|
+
self.setWidget(self.button)
|
937
|
+
self._postInit()
|
938
|
+
|
939
|
+
@__init__.register
|
940
|
+
def _(self, icon: FluentIconBase, parent: QWidget = None):
|
941
|
+
self.__init__(parent)
|
942
|
+
self.setIcon(icon)
|
943
|
+
|
944
|
+
@__init__.register
|
945
|
+
def _(self, icon: QIcon, parent: QWidget = None):
|
946
|
+
self.__init__(parent)
|
947
|
+
self.setIcon(icon)
|
948
|
+
|
949
|
+
@__init__.register
|
950
|
+
def _(self, icon: str, parent: QWidget = None):
|
951
|
+
self.__init__(parent)
|
952
|
+
self.setIcon(icon)
|
953
|
+
|
954
|
+
def _postInit(self):
|
955
|
+
pass
|
956
|
+
|
957
|
+
def icon(self):
|
958
|
+
return self.button.icon()
|
959
|
+
|
960
|
+
def setIcon(self, icon: Union[QIcon, FluentIconBase, str]):
|
961
|
+
self.button.setIcon(icon)
|
962
|
+
|
963
|
+
def setIconSize(self, size: QSize):
|
964
|
+
self.button.setIconSize(size)
|
965
|
+
|
966
|
+
icon_ = Property(QIcon, icon, setIcon)
|
967
|
+
|
968
|
+
|
969
|
+
class PrimarySplitToolButton(SplitToolButton):
|
970
|
+
""" Primary split push button
|
971
|
+
|
972
|
+
Constructors
|
973
|
+
------------
|
974
|
+
* PrimarySplitToolButton(`parent`: QWidget = None)
|
975
|
+
* PrimarySplitToolButton(`icon`: QIcon | str | FluentIconBase, `parent`: QWidget = None)
|
976
|
+
"""
|
977
|
+
|
978
|
+
def _postInit(self):
|
979
|
+
self.setDropButton(PrimarySplitDropButton(self))
|
980
|
+
|
981
|
+
self.hBoxLayout.removeWidget(self.button)
|
982
|
+
self.button.deleteLater()
|
983
|
+
|
984
|
+
self.button = PrimaryToolButton(self)
|
985
|
+
self.button.setObjectName('primarySplitToolButton')
|
986
|
+
self.button.clicked.connect(self.clicked)
|
987
|
+
self.setWidget(self.button)
|
988
|
+
|
989
|
+
|
990
|
+
class PillButtonBase:
|
991
|
+
""" Pill button base class """
|
992
|
+
|
993
|
+
def __init__(self, *args, **kwargs):
|
994
|
+
super().__init__(*args, **kwargs)
|
995
|
+
|
996
|
+
def paintEvent(self, e):
|
997
|
+
painter = QPainter(self)
|
998
|
+
painter.setRenderHints(QPainter.Antialiasing)
|
999
|
+
isDark = isDarkTheme()
|
1000
|
+
|
1001
|
+
if not self.isChecked():
|
1002
|
+
rect = self.rect().adjusted(1, 1, -1, -1)
|
1003
|
+
borderColor = QColor(255, 255, 255, 18) if isDark else QColor(0, 0, 0, 15)
|
1004
|
+
|
1005
|
+
if not self.isEnabled():
|
1006
|
+
bgColor = QColor(255, 255, 255, 11) if isDark else QColor(249, 249, 249, 75)
|
1007
|
+
elif self.isPressed or self.isHover:
|
1008
|
+
bgColor = QColor(255, 255, 255, 21) if isDark else QColor(249, 249, 249, 128)
|
1009
|
+
else:
|
1010
|
+
bgColor = QColor(255, 255, 255, 15) if isDark else QColor(243, 243, 243, 194)
|
1011
|
+
|
1012
|
+
else:
|
1013
|
+
if not self.isEnabled():
|
1014
|
+
bgColor = QColor(255, 255, 255, 40) if isDark else QColor(0, 0, 0, 55)
|
1015
|
+
elif self.isPressed:
|
1016
|
+
bgColor = ThemeColor.DARK_2.color() if isDark else ThemeColor.LIGHT_3.color()
|
1017
|
+
elif self.isHover:
|
1018
|
+
bgColor = ThemeColor.DARK_1.color() if isDark else ThemeColor.LIGHT_1.color()
|
1019
|
+
else:
|
1020
|
+
bgColor = themeColor()
|
1021
|
+
|
1022
|
+
borderColor = Qt.transparent
|
1023
|
+
rect = self.rect()
|
1024
|
+
|
1025
|
+
painter.setPen(borderColor)
|
1026
|
+
painter.setBrush(bgColor)
|
1027
|
+
|
1028
|
+
r = rect.height() / 2
|
1029
|
+
painter.drawRoundedRect(rect, r, r)
|
1030
|
+
|
1031
|
+
|
1032
|
+
class PillPushButton(TogglePushButton, PillButtonBase):
|
1033
|
+
""" Pill push button
|
1034
|
+
|
1035
|
+
Constructors
|
1036
|
+
------------
|
1037
|
+
* PillPushButton(`parent`: QWidget = None)
|
1038
|
+
* PillPushButton(`text`: str, `parent`: QWidget = None,
|
1039
|
+
`icon`: QIcon | str | FluentIconBase = None)
|
1040
|
+
* PillPushButton(`icon`: QIcon | FluentIcon, `text`: str, `parent`: QWidget = None)
|
1041
|
+
"""
|
1042
|
+
|
1043
|
+
def paintEvent(self, e):
|
1044
|
+
PillButtonBase.paintEvent(self, e)
|
1045
|
+
TogglePushButton.paintEvent(self, e)
|
1046
|
+
|
1047
|
+
|
1048
|
+
class PillToolButton(ToggleToolButton, PillButtonBase):
|
1049
|
+
""" Pill push button
|
1050
|
+
|
1051
|
+
Constructors
|
1052
|
+
------------
|
1053
|
+
* PillToolButton(`parent`: QWidget = None)
|
1054
|
+
* PillToolButton(`icon`: QIcon | str | FluentIconBase, `parent`: QWidget = None)
|
1055
|
+
"""
|
1056
|
+
|
1057
|
+
def paintEvent(self, e):
|
1058
|
+
PillButtonBase.paintEvent(self, e)
|
1059
|
+
ToggleToolButton.paintEvent(self, e)
|