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,556 @@
|
|
1
|
+
# coding:utf-8
|
2
|
+
import sys
|
3
|
+
from typing import Union, List, Iterable
|
4
|
+
|
5
|
+
from PySide6.QtCore import Qt, Signal, QRectF, QPoint, QObject, QEvent
|
6
|
+
from PySide6.QtGui import QPainter, QAction, QCursor, QIcon
|
7
|
+
from PySide6.QtWidgets import QPushButton, QApplication
|
8
|
+
|
9
|
+
from .menu import RoundMenu, MenuAnimationType, IndicatorMenuItemDelegate
|
10
|
+
from .line_edit import LineEdit, LineEditButton
|
11
|
+
from ...common.animation import TranslateYAnimation
|
12
|
+
from ...common.icon import FluentIconBase, isDarkTheme
|
13
|
+
from ...common.icon import FluentIcon as FIF
|
14
|
+
from ...common.font import setFont
|
15
|
+
from ...common.style_sheet import FluentStyleSheet
|
16
|
+
|
17
|
+
|
18
|
+
class ComboItem:
|
19
|
+
""" Combo box item """
|
20
|
+
|
21
|
+
def __init__(self, text: str, icon: Union[str, QIcon, FluentIconBase] = None, userData=None, isEnabled=True):
|
22
|
+
""" add item
|
23
|
+
|
24
|
+
Parameters
|
25
|
+
----------
|
26
|
+
text: str
|
27
|
+
the text of item
|
28
|
+
|
29
|
+
icon: str | QIcon | FluentIconBase
|
30
|
+
the icon of item
|
31
|
+
|
32
|
+
userData: Any
|
33
|
+
user data
|
34
|
+
|
35
|
+
isEnabled: bool
|
36
|
+
whether to enable the item
|
37
|
+
"""
|
38
|
+
self.text = text
|
39
|
+
self.userData = userData
|
40
|
+
self.icon = icon
|
41
|
+
self.isEnabled = isEnabled
|
42
|
+
|
43
|
+
@property
|
44
|
+
def icon(self):
|
45
|
+
if isinstance(self._icon, QIcon):
|
46
|
+
return self._icon
|
47
|
+
|
48
|
+
return self._icon.icon()
|
49
|
+
|
50
|
+
@icon.setter
|
51
|
+
def icon(self, ico: Union[str, QIcon, FluentIconBase]):
|
52
|
+
if ico:
|
53
|
+
self._icon = QIcon(ico) if isinstance(ico, str) else ico
|
54
|
+
else:
|
55
|
+
self._icon = QIcon()
|
56
|
+
|
57
|
+
|
58
|
+
class ComboBoxBase:
|
59
|
+
""" Combo box base """
|
60
|
+
activated = Signal(int)
|
61
|
+
textActivated = Signal(str)
|
62
|
+
|
63
|
+
def __init__(self, parent=None, **kwargs):
|
64
|
+
pass
|
65
|
+
|
66
|
+
def _setUpUi(self):
|
67
|
+
self.isHover = False
|
68
|
+
self.isPressed = False
|
69
|
+
self.items = [] # type: List[ComboItem]
|
70
|
+
self._currentIndex = -1
|
71
|
+
self._maxVisibleItems = -1
|
72
|
+
self.dropMenu = None
|
73
|
+
self._placeholderText = ""
|
74
|
+
|
75
|
+
FluentStyleSheet.COMBO_BOX.apply(self)
|
76
|
+
self.installEventFilter(self)
|
77
|
+
|
78
|
+
def addItem(self, text, icon: Union[str, QIcon, FluentIconBase] = None, userData=None):
|
79
|
+
""" add item
|
80
|
+
|
81
|
+
Parameters
|
82
|
+
----------
|
83
|
+
text: str
|
84
|
+
the text of item
|
85
|
+
|
86
|
+
icon: str | QIcon | FluentIconBase
|
87
|
+
"""
|
88
|
+
item = ComboItem(text, icon, userData)
|
89
|
+
self.items.append(item)
|
90
|
+
if len(self.items) == 1:
|
91
|
+
self.setCurrentIndex(0)
|
92
|
+
|
93
|
+
def addItems(self, texts: Iterable[str]):
|
94
|
+
""" add items
|
95
|
+
|
96
|
+
Parameters
|
97
|
+
----------
|
98
|
+
text: Iterable[str]
|
99
|
+
the text of item
|
100
|
+
"""
|
101
|
+
for text in texts:
|
102
|
+
self.addItem(text)
|
103
|
+
|
104
|
+
def removeItem(self, index: int):
|
105
|
+
""" Removes the item at the given index from the combobox.
|
106
|
+
This will update the current index if the index is removed.
|
107
|
+
"""
|
108
|
+
if not 0 <= index < len(self.items):
|
109
|
+
return
|
110
|
+
|
111
|
+
self.items.pop(index)
|
112
|
+
|
113
|
+
if index < self.currentIndex():
|
114
|
+
self.setCurrentIndex(self._currentIndex - 1)
|
115
|
+
elif index == self.currentIndex():
|
116
|
+
if index > 0:
|
117
|
+
self.setCurrentIndex(self._currentIndex - 1)
|
118
|
+
else:
|
119
|
+
self.setText(self.itemText(0))
|
120
|
+
self.currentTextChanged.emit(self.currentText())
|
121
|
+
self.currentIndexChanged.emit(0)
|
122
|
+
|
123
|
+
if self.count() == 0:
|
124
|
+
self.clear()
|
125
|
+
|
126
|
+
def currentIndex(self):
|
127
|
+
return self._currentIndex
|
128
|
+
|
129
|
+
def setCurrentIndex(self, index: int):
|
130
|
+
""" set current index
|
131
|
+
|
132
|
+
Parameters
|
133
|
+
----------
|
134
|
+
index: int
|
135
|
+
current index
|
136
|
+
"""
|
137
|
+
if not 0 <= index < len(self.items) or index == self.currentIndex():
|
138
|
+
return
|
139
|
+
|
140
|
+
oldText = self.currentText()
|
141
|
+
|
142
|
+
self._currentIndex = index
|
143
|
+
self.setText(self.items[index].text)
|
144
|
+
|
145
|
+
if oldText != self.currentText():
|
146
|
+
self.currentTextChanged.emit(self.currentText())
|
147
|
+
|
148
|
+
self.currentIndexChanged.emit(index)
|
149
|
+
|
150
|
+
def setText(self, text: str):
|
151
|
+
super().setText(text)
|
152
|
+
self.adjustSize()
|
153
|
+
|
154
|
+
def currentText(self):
|
155
|
+
if not 0 <= self.currentIndex() < len(self.items):
|
156
|
+
return ''
|
157
|
+
|
158
|
+
return self.items[self.currentIndex()].text
|
159
|
+
|
160
|
+
def currentData(self):
|
161
|
+
if not 0 <= self.currentIndex() < len(self.items):
|
162
|
+
return None
|
163
|
+
|
164
|
+
return self.items[self.currentIndex()].userData
|
165
|
+
|
166
|
+
def setCurrentText(self, text):
|
167
|
+
""" set the current text displayed in combo box,
|
168
|
+
text should be in the item list
|
169
|
+
|
170
|
+
Parameters
|
171
|
+
----------
|
172
|
+
text: str
|
173
|
+
text displayed in combo box
|
174
|
+
"""
|
175
|
+
if text == self.currentText():
|
176
|
+
return
|
177
|
+
|
178
|
+
index = self.findText(text)
|
179
|
+
if index >= 0:
|
180
|
+
self.setCurrentIndex(index)
|
181
|
+
|
182
|
+
def setItemText(self, index: int, text: str):
|
183
|
+
""" set the text of item
|
184
|
+
|
185
|
+
Parameters
|
186
|
+
----------
|
187
|
+
index: int
|
188
|
+
the index of item
|
189
|
+
|
190
|
+
text: str
|
191
|
+
new text of item
|
192
|
+
"""
|
193
|
+
if not 0 <= index < len(self.items):
|
194
|
+
return
|
195
|
+
|
196
|
+
self.items[index].text = text
|
197
|
+
if self.currentIndex() == index:
|
198
|
+
self.setText(text)
|
199
|
+
|
200
|
+
def itemData(self, index: int):
|
201
|
+
""" Returns the data in the given index """
|
202
|
+
if not 0 <= index < len(self.items):
|
203
|
+
return None
|
204
|
+
|
205
|
+
return self.items[index].userData
|
206
|
+
|
207
|
+
def itemText(self, index: int):
|
208
|
+
""" Returns the text in the given index """
|
209
|
+
if not 0 <= index < len(self.items):
|
210
|
+
return ''
|
211
|
+
|
212
|
+
return self.items[index].text
|
213
|
+
|
214
|
+
def itemIcon(self, index: int):
|
215
|
+
""" Returns the icon in the given index """
|
216
|
+
if not 0 <= index < len(self.items):
|
217
|
+
return QIcon()
|
218
|
+
|
219
|
+
return self.items[index].icon
|
220
|
+
|
221
|
+
def setItemData(self, index: int, value):
|
222
|
+
""" Sets the data role for the item on the given index """
|
223
|
+
if 0 <= index < len(self.items):
|
224
|
+
self.items[index].userData = value
|
225
|
+
|
226
|
+
def setItemIcon(self, index: int, icon: Union[str, QIcon, FluentIconBase]):
|
227
|
+
""" Sets the data role for the item on the given index """
|
228
|
+
if 0 <= index < len(self.items):
|
229
|
+
self.items[index].icon = icon
|
230
|
+
|
231
|
+
def setItemEnabled(self, index: int, isEnabled: bool):
|
232
|
+
""" Sets the enabled status of the item on the given index """
|
233
|
+
if 0 <= index < len(self.items):
|
234
|
+
self.items[index].isEnabled = isEnabled
|
235
|
+
|
236
|
+
def findData(self, data):
|
237
|
+
""" Returns the index of the item containing the given data, otherwise returns -1 """
|
238
|
+
for i, item in enumerate(self.items):
|
239
|
+
if item.userData == data:
|
240
|
+
return i
|
241
|
+
|
242
|
+
return -1
|
243
|
+
|
244
|
+
def findText(self, text: str):
|
245
|
+
""" Returns the index of the item containing the given text; otherwise returns -1. """
|
246
|
+
for i, item in enumerate(self.items):
|
247
|
+
if item.text == text:
|
248
|
+
return i
|
249
|
+
|
250
|
+
return -1
|
251
|
+
|
252
|
+
def clear(self):
|
253
|
+
""" Clears the combobox, removing all items. """
|
254
|
+
if self.currentIndex() >= 0:
|
255
|
+
self.setText('')
|
256
|
+
|
257
|
+
self.items.clear()
|
258
|
+
self._currentIndex = -1
|
259
|
+
|
260
|
+
def count(self):
|
261
|
+
""" Returns the number of items in the combobox """
|
262
|
+
return len(self.items)
|
263
|
+
|
264
|
+
def insertItem(self, index: int, text: str, icon: Union[str, QIcon, FluentIconBase] = None, userData=None):
|
265
|
+
""" Inserts item into the combobox at the given index. """
|
266
|
+
item = ComboItem(text, icon, userData)
|
267
|
+
self.items.insert(index, item)
|
268
|
+
|
269
|
+
if index <= self.currentIndex():
|
270
|
+
self.setCurrentIndex(self.currentIndex() + 1)
|
271
|
+
|
272
|
+
def insertItems(self, index: int, texts: Iterable[str]):
|
273
|
+
""" Inserts items into the combobox, starting at the index specified. """
|
274
|
+
pos = index
|
275
|
+
for text in texts:
|
276
|
+
item = ComboItem(text)
|
277
|
+
self.items.insert(pos, item)
|
278
|
+
pos += 1
|
279
|
+
|
280
|
+
if index <= self.currentIndex():
|
281
|
+
self.setCurrentIndex(self.currentIndex() + pos - index)
|
282
|
+
|
283
|
+
def setMaxVisibleItems(self, num: int):
|
284
|
+
self._maxVisibleItems = num
|
285
|
+
|
286
|
+
def maxVisibleItems(self):
|
287
|
+
return self._maxVisibleItems
|
288
|
+
|
289
|
+
def _closeComboMenu(self):
|
290
|
+
if not self.dropMenu:
|
291
|
+
return
|
292
|
+
|
293
|
+
# drop menu could be deleted before this method
|
294
|
+
try:
|
295
|
+
self.dropMenu.close()
|
296
|
+
except:
|
297
|
+
pass
|
298
|
+
|
299
|
+
self.dropMenu = None
|
300
|
+
|
301
|
+
def _onDropMenuClosed(self):
|
302
|
+
if sys.platform != "win32":
|
303
|
+
self.dropMenu = None
|
304
|
+
else:
|
305
|
+
pos = self.mapFromGlobal(QCursor.pos())
|
306
|
+
if not self.rect().contains(pos):
|
307
|
+
self.dropMenu = None
|
308
|
+
|
309
|
+
def _createComboMenu(self):
|
310
|
+
return ComboBoxMenu(self)
|
311
|
+
|
312
|
+
def _showComboMenu(self):
|
313
|
+
if not self.items:
|
314
|
+
return
|
315
|
+
|
316
|
+
menu = self._createComboMenu()
|
317
|
+
for item in self.items:
|
318
|
+
action = QAction(item.icon, item.text)
|
319
|
+
action.setEnabled(item.isEnabled)
|
320
|
+
menu.addAction(action)
|
321
|
+
|
322
|
+
# fixes issue #468
|
323
|
+
menu.view.itemClicked.connect(lambda i: self._onItemClicked(self.findText(i.text().lstrip())))
|
324
|
+
|
325
|
+
if menu.view.width() < self.width():
|
326
|
+
menu.view.setMinimumWidth(self.width())
|
327
|
+
menu.adjustSize()
|
328
|
+
|
329
|
+
menu.setMaxVisibleItems(self.maxVisibleItems())
|
330
|
+
menu.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
|
331
|
+
menu.closedSignal.connect(self._onDropMenuClosed)
|
332
|
+
self.dropMenu = menu
|
333
|
+
|
334
|
+
# set the selected item
|
335
|
+
if self.currentIndex() >= 0 and self.items:
|
336
|
+
menu.setDefaultAction(menu.actions()[self.currentIndex()])
|
337
|
+
|
338
|
+
# determine the animation type by choosing the maximum height of view
|
339
|
+
x = -menu.width()//2 + menu.layout().contentsMargins().left() + self.width()//2
|
340
|
+
pd = self.mapToGlobal(QPoint(x, self.height()))
|
341
|
+
hd = menu.view.heightForAnimation(pd, MenuAnimationType.DROP_DOWN)
|
342
|
+
|
343
|
+
pu = self.mapToGlobal(QPoint(x, 0))
|
344
|
+
hu = menu.view.heightForAnimation(pu, MenuAnimationType.PULL_UP)
|
345
|
+
|
346
|
+
if hd >= hu:
|
347
|
+
menu.view.adjustSize(pd, MenuAnimationType.DROP_DOWN)
|
348
|
+
menu.exec(pd, aniType=MenuAnimationType.DROP_DOWN)
|
349
|
+
else:
|
350
|
+
menu.view.adjustSize(pu, MenuAnimationType.PULL_UP)
|
351
|
+
menu.exec(pu, aniType=MenuAnimationType.PULL_UP)
|
352
|
+
|
353
|
+
def _toggleComboMenu(self):
|
354
|
+
if self.dropMenu:
|
355
|
+
self._closeComboMenu()
|
356
|
+
else:
|
357
|
+
self._showComboMenu()
|
358
|
+
|
359
|
+
def _onItemClicked(self, index):
|
360
|
+
if not self.items[index].isEnabled:
|
361
|
+
return
|
362
|
+
|
363
|
+
if index != self.currentIndex():
|
364
|
+
self.setCurrentIndex(index)
|
365
|
+
|
366
|
+
self.activated.emit(index)
|
367
|
+
self.textActivated.emit(self.currentText())
|
368
|
+
|
369
|
+
|
370
|
+
class ComboBox(QPushButton, ComboBoxBase):
|
371
|
+
""" Combo box """
|
372
|
+
|
373
|
+
currentIndexChanged = Signal(int)
|
374
|
+
currentTextChanged = Signal(str)
|
375
|
+
activated = Signal(int)
|
376
|
+
textActivated = Signal(str)
|
377
|
+
|
378
|
+
def __init__(self, parent=None):
|
379
|
+
super().__init__(parent=parent)
|
380
|
+
self.arrowAni = TranslateYAnimation(self)
|
381
|
+
self._setUpUi()
|
382
|
+
setFont(self)
|
383
|
+
|
384
|
+
def eventFilter(self, obj, e: QEvent):
|
385
|
+
if obj is self:
|
386
|
+
if e.type() == QEvent.MouseButtonPress:
|
387
|
+
self.isPressed = True
|
388
|
+
elif e.type() == QEvent.MouseButtonRelease:
|
389
|
+
self.isPressed = False
|
390
|
+
elif e.type() == QEvent.Enter:
|
391
|
+
self.isHover = True
|
392
|
+
elif e.type() == QEvent.Leave:
|
393
|
+
self.isHover = False
|
394
|
+
|
395
|
+
return super().eventFilter(obj, e)
|
396
|
+
|
397
|
+
def setPlaceholderText(self, text: str):
|
398
|
+
self._placeholderText = text
|
399
|
+
|
400
|
+
if self.currentIndex() <= 0:
|
401
|
+
self._updateTextState(True)
|
402
|
+
self.setText(text)
|
403
|
+
|
404
|
+
def setCurrentIndex(self, index: int):
|
405
|
+
if index < 0:
|
406
|
+
self._currentIndex = -1
|
407
|
+
self.setPlaceholderText(self._placeholderText)
|
408
|
+
elif 0 <= index < len(self.items):
|
409
|
+
self._updateTextState(False)
|
410
|
+
super().setCurrentIndex(index)
|
411
|
+
|
412
|
+
def _updateTextState(self, isPlaceholder):
|
413
|
+
if self.property("isPlaceholderText") == isPlaceholder:
|
414
|
+
return
|
415
|
+
|
416
|
+
self.setProperty("isPlaceholderText", isPlaceholder)
|
417
|
+
self.setStyle(QApplication.style())
|
418
|
+
|
419
|
+
def mouseReleaseEvent(self, e):
|
420
|
+
super().mouseReleaseEvent(e)
|
421
|
+
self._toggleComboMenu()
|
422
|
+
|
423
|
+
def paintEvent(self, e):
|
424
|
+
QPushButton.paintEvent(self, e)
|
425
|
+
painter = QPainter(self)
|
426
|
+
painter.setRenderHints(QPainter.Antialiasing)
|
427
|
+
if self.isHover:
|
428
|
+
painter.setOpacity(0.8)
|
429
|
+
elif self.isPressed:
|
430
|
+
painter.setOpacity(0.7)
|
431
|
+
|
432
|
+
rect = QRectF(self.width()-22, self.height()/2-5+self.arrowAni.y, 10, 10)
|
433
|
+
if isDarkTheme():
|
434
|
+
FIF.ARROW_DOWN.render(painter, rect)
|
435
|
+
else:
|
436
|
+
FIF.ARROW_DOWN.render(painter, rect, fill="#646464")
|
437
|
+
|
438
|
+
|
439
|
+
class EditableComboBox(LineEdit, ComboBoxBase):
|
440
|
+
""" Editable combo box """
|
441
|
+
|
442
|
+
currentIndexChanged = Signal(int)
|
443
|
+
currentTextChanged = Signal(str)
|
444
|
+
activated = Signal(int)
|
445
|
+
textActivated = Signal(str)
|
446
|
+
|
447
|
+
def __init__(self, parent=None):
|
448
|
+
super().__init__(parent=parent)
|
449
|
+
self._setUpUi()
|
450
|
+
|
451
|
+
self.dropButton = LineEditButton(FIF.ARROW_DOWN, self)
|
452
|
+
|
453
|
+
self.setTextMargins(0, 0, 29, 0)
|
454
|
+
self.dropButton.setFixedSize(30, 25)
|
455
|
+
self.hBoxLayout.addWidget(self.dropButton, 0, Qt.AlignRight)
|
456
|
+
|
457
|
+
self.dropButton.clicked.connect(self._toggleComboMenu)
|
458
|
+
self.textChanged.connect(self._onComboTextChanged)
|
459
|
+
self.returnPressed.connect(self._onReturnPressed)
|
460
|
+
|
461
|
+
FluentStyleSheet.LINE_EDIT.apply(self)
|
462
|
+
|
463
|
+
self.clearButton.clicked.disconnect()
|
464
|
+
self.clearButton.clicked.connect(self._onClearButtonClicked)
|
465
|
+
|
466
|
+
def setCompleterMenu(self, menu):
|
467
|
+
super().setCompleterMenu(menu)
|
468
|
+
menu.activated.connect(self.__onActivated)
|
469
|
+
|
470
|
+
def __onActivated(self, text):
|
471
|
+
index = self.findText(text)
|
472
|
+
if index >= 0:
|
473
|
+
self.setCurrentIndex(index)
|
474
|
+
|
475
|
+
def currentText(self):
|
476
|
+
return self.text()
|
477
|
+
|
478
|
+
def setCurrentIndex(self, index: int):
|
479
|
+
if index >= self.count() or index == self.currentIndex():
|
480
|
+
return
|
481
|
+
|
482
|
+
if index < 0:
|
483
|
+
self._currentIndex = -1
|
484
|
+
self.setText("")
|
485
|
+
self.setPlaceholderText(self._placeholderText)
|
486
|
+
else:
|
487
|
+
self._currentIndex = index
|
488
|
+
self.setText(self.items[index].text)
|
489
|
+
|
490
|
+
def clear(self):
|
491
|
+
ComboBoxBase.clear(self)
|
492
|
+
|
493
|
+
def setPlaceholderText(self, text: str):
|
494
|
+
self._placeholderText = text
|
495
|
+
super().setPlaceholderText(text)
|
496
|
+
|
497
|
+
def _onReturnPressed(self):
|
498
|
+
if not self.text():
|
499
|
+
return
|
500
|
+
|
501
|
+
index = self.findText(self.text())
|
502
|
+
if index >= 0 and index != self.currentIndex():
|
503
|
+
self._currentIndex = index
|
504
|
+
self.currentIndexChanged.emit(index)
|
505
|
+
elif index == -1:
|
506
|
+
self.addItem(self.text())
|
507
|
+
self.setCurrentIndex(self.count() - 1)
|
508
|
+
|
509
|
+
def eventFilter(self, obj, e: QEvent):
|
510
|
+
if obj is self:
|
511
|
+
if e.type() == QEvent.MouseButtonPress:
|
512
|
+
self.isPressed = True
|
513
|
+
elif e.type() == QEvent.MouseButtonRelease:
|
514
|
+
self.isPressed = False
|
515
|
+
elif e.type() == QEvent.Enter:
|
516
|
+
self.isHover = True
|
517
|
+
elif e.type() == QEvent.Leave:
|
518
|
+
self.isHover = False
|
519
|
+
|
520
|
+
return super().eventFilter(obj, e)
|
521
|
+
|
522
|
+
def _onComboTextChanged(self, text: str):
|
523
|
+
self._currentIndex = -1
|
524
|
+
self.currentTextChanged.emit(text)
|
525
|
+
|
526
|
+
for i, item in enumerate(self.items):
|
527
|
+
if item.text == text:
|
528
|
+
self._currentIndex = i
|
529
|
+
self.currentIndexChanged.emit(i)
|
530
|
+
return
|
531
|
+
|
532
|
+
def _onDropMenuClosed(self):
|
533
|
+
self.dropMenu = None
|
534
|
+
|
535
|
+
def _onClearButtonClicked(self):
|
536
|
+
LineEdit.clear(self)
|
537
|
+
self._currentIndex = -1
|
538
|
+
|
539
|
+
|
540
|
+
class ComboBoxMenu(RoundMenu):
|
541
|
+
""" Combo box menu """
|
542
|
+
|
543
|
+
def __init__(self, parent=None):
|
544
|
+
super().__init__(title="", parent=parent)
|
545
|
+
|
546
|
+
self.view.setViewportMargins(0, 2, 0, 6)
|
547
|
+
self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
548
|
+
self.view.setItemDelegate(IndicatorMenuItemDelegate())
|
549
|
+
self.view.setObjectName('comboListWidget')
|
550
|
+
|
551
|
+
self.setItemHeight(33)
|
552
|
+
|
553
|
+
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
554
|
+
self.view.adjustSize(pos, aniType)
|
555
|
+
self.adjustSize()
|
556
|
+
return super().exec(pos, ani, aniType)
|