PySide6Plot 0.0.1__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.
- PySide6Plot/__init__.py +187 -0
- PySide6Plot/compoents/__init__.py +3 -0
- PySide6Plot/compoents/average_line.py +232 -0
- PySide6Plot/compoents/draw_line.py +624 -0
- PySide6Plot/compoents/frame_recorder.py +213 -0
- PySide6Plot/compoents/zoom_move.py +160 -0
- PySide6Plot/libs/__init__.py +3 -0
- PySide6Plot/libs/constant.py +19 -0
- PySide6Plot/libs/data_handler.py +230 -0
- PySide6Plot/libs/helpers.py +401 -0
- PySide6Plot/libs/plot_item.py +233 -0
- PySide6Plot/libs/style.py +119 -0
- PySide6Plot/resources/icons/ChevronLeft_black.svg +44 -0
- PySide6Plot/resources/icons/ChevronLeft_white.svg +44 -0
- PySide6Plot/resources/qss/dark/navigation_view_interface.qss +16 -0
- PySide6Plot/resources/qss/light/navigation_view_interface.qss +16 -0
- PySide6Plot/widgets/__init__.py +3 -0
- PySide6Plot/widgets/colorful_toggle_button.py +131 -0
- PySide6Plot/widgets/fluent_scroller.py +450 -0
- PySide6Plot/widgets/line_card.py +138 -0
- PySide6Plot/widgets/navigation_widget.py +49 -0
- PySide6Plot/widgets/q_plot_widget.py +750 -0
- PySide6Plot/widgets/removable_table.py +259 -0
- PySide6Plot/widgets/transparent_Line_edit.py +69 -0
- PySide6Plot/widgets/transparent_selector.py +208 -0
- PySide6Plot/widgets/value_select_box.py +369 -0
- PySide6Plot/widgets/zoom_bar.py +136 -0
- pyside6plot-0.0.1.dist-info/METADATA +37 -0
- pyside6plot-0.0.1.dist-info/RECORD +31 -0
- pyside6plot-0.0.1.dist-info/WHEEL +5 -0
- pyside6plot-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
from qfluentwidgets import (
|
|
2
|
+
FluentIcon,
|
|
3
|
+
Action,
|
|
4
|
+
Flyout,
|
|
5
|
+
FlyoutAnimationType,
|
|
6
|
+
TableWidget,
|
|
7
|
+
CommandBarView,
|
|
8
|
+
TableItemDelegate,
|
|
9
|
+
)
|
|
10
|
+
from PySide6.QtWidgets import QTableView, QTableWidgetItem
|
|
11
|
+
from PySide6.QtCore import Qt, Signal, QEvent, QModelIndex
|
|
12
|
+
from PySide6.QtGui import QCursor
|
|
13
|
+
from PySide6.QtWidgets import QWidget, QStyleOptionViewItem
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# https://forum.qt.io/topic/97628/qlistwidget-item-editing/13
|
|
17
|
+
class JEditableListStyledItemDelegate(TableItemDelegate):
|
|
18
|
+
# class variable for "editStarted" signal, with QModelIndex parameter
|
|
19
|
+
editStarted = Signal(QModelIndex, name="editStarted")
|
|
20
|
+
# class variable for "editFinished" signal, with QModelIndex parameter
|
|
21
|
+
editFinished = Signal(QModelIndex, name="editFinished")
|
|
22
|
+
|
|
23
|
+
def __init__(self, parent: QTableView):
|
|
24
|
+
super().__init__(parent)
|
|
25
|
+
self.edit_created = False
|
|
26
|
+
|
|
27
|
+
def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex):
|
|
28
|
+
editor = super().createEditor(parent, option, index)
|
|
29
|
+
self.edit_created = True
|
|
30
|
+
if editor is not None:
|
|
31
|
+
self.editStarted.emit(index)
|
|
32
|
+
return editor
|
|
33
|
+
|
|
34
|
+
def destroyEditor(self, editor: QWidget, index: QModelIndex):
|
|
35
|
+
if self.edit_created:
|
|
36
|
+
self.editFinished.emit(index)
|
|
37
|
+
self.edit_created = False
|
|
38
|
+
return super().destroyEditor(editor, index)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class RemovableTable(TableWidget):
|
|
42
|
+
sigAcceptClicked = Signal(int)
|
|
43
|
+
sigRowClicked = Signal(int)
|
|
44
|
+
sigDeleteClicked = Signal(int)
|
|
45
|
+
sigMoveUpClicked = Signal(int)
|
|
46
|
+
sigMoveDownClicked = Signal(int)
|
|
47
|
+
sigNameEdited = Signal(int, str)
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
parent=None,
|
|
52
|
+
show_row_index=False,
|
|
53
|
+
resize_columns_to_contents=True,
|
|
54
|
+
show_move_up_down_buttons=True,
|
|
55
|
+
show_delete_button=True,
|
|
56
|
+
show_rename_button=True,
|
|
57
|
+
accept_name="Select",
|
|
58
|
+
accept_icon=FluentIcon.ACCEPT,
|
|
59
|
+
link_default_slot=True,
|
|
60
|
+
):
|
|
61
|
+
super().__init__(parent)
|
|
62
|
+
self.setBorderVisible(True)
|
|
63
|
+
self.setBorderRadius(8)
|
|
64
|
+
self.setWordWrap(False)
|
|
65
|
+
self.viewport().installEventFilter(self)
|
|
66
|
+
styledItemDelegate = JEditableListStyledItemDelegate(self)
|
|
67
|
+
styledItemDelegate.editFinished.connect(self.__on_name_changed)
|
|
68
|
+
self.setItemDelegate(styledItemDelegate)
|
|
69
|
+
self.current_item = None
|
|
70
|
+
self.show_row_index = show_row_index
|
|
71
|
+
self.resize_columns_to_contents = resize_columns_to_contents
|
|
72
|
+
self.show_move_up_down_buttons = show_move_up_down_buttons
|
|
73
|
+
self.show_delete_button = show_delete_button
|
|
74
|
+
self.show_rename_button = show_rename_button
|
|
75
|
+
self.accept_name = accept_name
|
|
76
|
+
self.accept_icon = accept_icon
|
|
77
|
+
self.act_from_self = False
|
|
78
|
+
if not self.show_row_index:
|
|
79
|
+
self.verticalHeader().hide()
|
|
80
|
+
if link_default_slot:
|
|
81
|
+
self.sigAcceptClicked.connect(self.accept_row_data)
|
|
82
|
+
self.sigDeleteClicked.connect(self.delete_row_data)
|
|
83
|
+
self.sigMoveUpClicked.connect(self.move_up_row_data)
|
|
84
|
+
self.sigMoveDownClicked.connect(self.move_down_row_data)
|
|
85
|
+
|
|
86
|
+
def show_menu_bar(self):
|
|
87
|
+
"""
|
|
88
|
+
Show the menu bar with various actions such as accept, rename, move up, move down, and delete.
|
|
89
|
+
NOTE: Must specify the current item before calling this method.
|
|
90
|
+
"""
|
|
91
|
+
self.command_bar = CommandBarView(self)
|
|
92
|
+
select_action = Action(self.accept_icon, self.accept_name)
|
|
93
|
+
select_action.triggered.connect(self.__on_accept_clicked)
|
|
94
|
+
self.command_bar.addAction(select_action)
|
|
95
|
+
if self.show_rename_button:
|
|
96
|
+
edit_action = Action(FluentIcon.FONT, "Rename")
|
|
97
|
+
edit_action.triggered.connect(self.__on_edit_row_clicked)
|
|
98
|
+
self.command_bar.addAction(edit_action)
|
|
99
|
+
if self.show_move_up_down_buttons:
|
|
100
|
+
if self.current_item.row() > 0:
|
|
101
|
+
move_up_action = Action(FluentIcon.UP, "Move up")
|
|
102
|
+
move_up_action.triggered.connect(self.__on_move_up_row_clicked)
|
|
103
|
+
self.command_bar.addAction(move_up_action)
|
|
104
|
+
if self.current_item.row() < self.rowCount() - 1:
|
|
105
|
+
move_down_action = Action(FluentIcon.DOWN, "Move down")
|
|
106
|
+
move_down_action.triggered.connect(self.__on_move_down_row_clicked)
|
|
107
|
+
self.command_bar.addAction(move_down_action)
|
|
108
|
+
if self.show_delete_button:
|
|
109
|
+
delete_action = Action(FluentIcon.DELETE, "Delete")
|
|
110
|
+
delete_action.triggered.connect(self.__on_delete_row_clicked)
|
|
111
|
+
self.command_bar.addAction(delete_action)
|
|
112
|
+
self.command_bar.resizeToSuitableWidth()
|
|
113
|
+
self.shown_cbar = Flyout.make(self.command_bar, QCursor.pos(), self, FlyoutAnimationType.FADE_IN, True)
|
|
114
|
+
|
|
115
|
+
def accept_row_data(self, row_index):
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
def __on_accept_clicked(self):
|
|
119
|
+
if self.current_item is not None:
|
|
120
|
+
self.clearSelection()
|
|
121
|
+
self.shown_cbar.close()
|
|
122
|
+
self.sigAcceptClicked.emit(self.current_item.row())
|
|
123
|
+
self.current_item = None
|
|
124
|
+
|
|
125
|
+
def delete_row_data(self, row_index):
|
|
126
|
+
"""
|
|
127
|
+
Delete a row of data from the table.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
row_index (int): The index of the row to be deleted.
|
|
131
|
+
"""
|
|
132
|
+
self.removeRow(row_index)
|
|
133
|
+
|
|
134
|
+
def __on_delete_row_clicked(self):
|
|
135
|
+
if self.current_item is not None:
|
|
136
|
+
self.clearSelection()
|
|
137
|
+
self.shown_cbar.close()
|
|
138
|
+
self.sigDeleteClicked.emit(self.current_item.row())
|
|
139
|
+
self.current_item = None
|
|
140
|
+
|
|
141
|
+
def move_up_row_data(self, row_index):
|
|
142
|
+
"""
|
|
143
|
+
Moves the data in the specified row up by one row.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
row_index (int): The index of the row to move up.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
None
|
|
150
|
+
"""
|
|
151
|
+
for j in range(self.columnCount()):
|
|
152
|
+
temple = self.item(row_index, j).text()
|
|
153
|
+
self.item(row_index, j).setText(self.item(row_index - 1, j).text())
|
|
154
|
+
self.item(row_index - 1, j).setText(temple)
|
|
155
|
+
|
|
156
|
+
def __on_move_up_row_clicked(self):
|
|
157
|
+
if self.current_item is not None:
|
|
158
|
+
self.clearSelection()
|
|
159
|
+
self.shown_cbar.close()
|
|
160
|
+
self.sigMoveUpClicked.emit(self.current_item.row())
|
|
161
|
+
self.current_item = None
|
|
162
|
+
|
|
163
|
+
def move_down_row_data(self, row_index, mute_signal=False):
|
|
164
|
+
"""
|
|
165
|
+
Move the data in the specified row down by one row.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
row_index (int): The index of the row to move down.
|
|
169
|
+
mute_signal (bool, optional): Whether to mute the signal emitted during the move. Defaults to False.
|
|
170
|
+
"""
|
|
171
|
+
for j in range(self.columnCount()):
|
|
172
|
+
temple = self.item(row_index, j).text()
|
|
173
|
+
self.item(row_index, j).setText(self.item(row_index + 1, j).text())
|
|
174
|
+
self.item(row_index + 1, j).setText(temple)
|
|
175
|
+
|
|
176
|
+
def __on_move_down_row_clicked(self):
|
|
177
|
+
if self.current_item is not None:
|
|
178
|
+
self.clearSelection()
|
|
179
|
+
self.shown_cbar.close()
|
|
180
|
+
self.sigMoveDownClicked.emit(self.current_item.row())
|
|
181
|
+
self.current_item = None
|
|
182
|
+
|
|
183
|
+
def rename(self, row_index):
|
|
184
|
+
self.editItem(self.item(row_index, 0))
|
|
185
|
+
|
|
186
|
+
def __on_edit_row_clicked(self):
|
|
187
|
+
if self.current_item is not None:
|
|
188
|
+
self.rename(self.current_item.row())
|
|
189
|
+
self.shown_cbar.close()
|
|
190
|
+
|
|
191
|
+
def __on_name_changed(self, index):
|
|
192
|
+
self.sigNameEdited.emit(index.row(), index.data())
|
|
193
|
+
|
|
194
|
+
def set_header_labels(self, labels):
|
|
195
|
+
"""
|
|
196
|
+
Set the header labels for the table.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
labels (list): A list of strings representing the header labels.
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
None
|
|
203
|
+
"""
|
|
204
|
+
self.setColumnCount(len(labels))
|
|
205
|
+
self.setHorizontalHeaderLabels(labels)
|
|
206
|
+
if self.resize_columns_to_contents:
|
|
207
|
+
self.resizeColumnsToContents()
|
|
208
|
+
|
|
209
|
+
def set_row_data_item(self, row_index, col_index, item):
|
|
210
|
+
"""
|
|
211
|
+
Sets the data item for a specific row and column in the table.
|
|
212
|
+
|
|
213
|
+
Parameters:
|
|
214
|
+
row_index (int): The index of the row.
|
|
215
|
+
col_index (int): The index of the column.
|
|
216
|
+
item (QWidget or any): The item to be set in the table.
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
None
|
|
220
|
+
"""
|
|
221
|
+
if isinstance(item, QWidget):
|
|
222
|
+
item_text = " "
|
|
223
|
+
self.setItem(row_index, col_index, QTableWidgetItem(item_text))
|
|
224
|
+
self.setCellWidget(row_index, col_index, item)
|
|
225
|
+
else:
|
|
226
|
+
item = QTableWidgetItem(str(item))
|
|
227
|
+
if col_index != 0:
|
|
228
|
+
item.setFlags(item.flags() & ~Qt.ItemFlag.ItemIsEditable)
|
|
229
|
+
self.setItem(row_index, col_index, item)
|
|
230
|
+
|
|
231
|
+
def add_row_data(self, data_i):
|
|
232
|
+
"""
|
|
233
|
+
Add a new row to the table and populate it with the given data.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
data_i (list): The data to be added to the new row.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
None
|
|
240
|
+
"""
|
|
241
|
+
row_count = self.rowCount()
|
|
242
|
+
self.setRowCount(row_count + 1)
|
|
243
|
+
for j, content in enumerate(data_i):
|
|
244
|
+
self.set_row_data_item(row_count, j, content)
|
|
245
|
+
if self.resize_columns_to_contents:
|
|
246
|
+
self.resizeColumnsToContents()
|
|
247
|
+
|
|
248
|
+
def eventFilter(self, source, event):
|
|
249
|
+
if event.type() == QEvent.Type.MouseButtonPress:
|
|
250
|
+
item = self.itemAt(event.pos())
|
|
251
|
+
if item is not None:
|
|
252
|
+
self.current_item = item
|
|
253
|
+
self.clearSelection()
|
|
254
|
+
self.selectRow(self.current_item.row())
|
|
255
|
+
if event.button() == Qt.MouseButton.LeftButton:
|
|
256
|
+
self.sigRowClicked.emit(self.current_item.row())
|
|
257
|
+
elif event.button() == Qt.MouseButton.RightButton:
|
|
258
|
+
self.show_menu_bar()
|
|
259
|
+
return super().eventFilter(source, event)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from PySide6.QtCore import QEvent, QObject
|
|
2
|
+
from qfluentwidgets import TransparentPushButton, LineEdit
|
|
3
|
+
from PySide6.QtWidgets import QWidget, QVBoxLayout
|
|
4
|
+
from PySide6.QtCore import Signal, Qt
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TransparentLineEdit(QWidget):
|
|
8
|
+
sigTextEditFinished = Signal()
|
|
9
|
+
|
|
10
|
+
def __init__(self, parent=None):
|
|
11
|
+
super().__init__(parent=parent)
|
|
12
|
+
self.main_layout = QVBoxLayout()
|
|
13
|
+
self.main_layout.setContentsMargins(0, 0, 0, 0)
|
|
14
|
+
self.main_layout.setSpacing(0)
|
|
15
|
+
self.line_edit = LineEdit(parent=self)
|
|
16
|
+
self.push_button = TransparentPushButton(parent=self)
|
|
17
|
+
self.main_layout.addWidget(self.line_edit)
|
|
18
|
+
self.main_layout.addWidget(self.push_button)
|
|
19
|
+
self.line_edit.setVisible(False)
|
|
20
|
+
self.setLayout(self.main_layout)
|
|
21
|
+
self.push_button.clicked.connect(self.__show_line_edit)
|
|
22
|
+
self.line_edit.installEventFilter(self)
|
|
23
|
+
|
|
24
|
+
def set_text(self, text):
|
|
25
|
+
self.line_edit.setText(text)
|
|
26
|
+
self.push_button.setText(text)
|
|
27
|
+
|
|
28
|
+
def get_text(self):
|
|
29
|
+
return self.line_edit.text()
|
|
30
|
+
|
|
31
|
+
def __show_line_edit(self):
|
|
32
|
+
self.push_button.setVisible(False)
|
|
33
|
+
self.line_edit.setVisible(True)
|
|
34
|
+
self.line_edit.setFocus()
|
|
35
|
+
|
|
36
|
+
def __finish_edit(self):
|
|
37
|
+
self.sigTextEditFinished.emit()
|
|
38
|
+
self.push_button.setText(self.line_edit.text())
|
|
39
|
+
self.line_edit.setVisible(False)
|
|
40
|
+
self.push_button.setVisible(True)
|
|
41
|
+
|
|
42
|
+
def eventFilter(self, a0: QObject, a1: QEvent) -> bool:
|
|
43
|
+
if a0 == self.line_edit:
|
|
44
|
+
if a1.type() == QEvent.Type.FocusOut:
|
|
45
|
+
self.__finish_edit()
|
|
46
|
+
return False
|
|
47
|
+
if a1.type() == QEvent.Type.KeyPress:
|
|
48
|
+
if a1.key() in (Qt.Key.Key_Enter, Qt.Key.Key_Return):
|
|
49
|
+
self.__finish_edit()
|
|
50
|
+
return False
|
|
51
|
+
elif a1.key() == Qt.Key.Key_Escape:
|
|
52
|
+
self.line_edit.setVisible(False)
|
|
53
|
+
self.push_button.setVisible(True)
|
|
54
|
+
return False
|
|
55
|
+
return super().eventFilter(a0, a1)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
from PySide6.QtWidgets import QApplication
|
|
60
|
+
import sys
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
app = QApplication(sys.argv)
|
|
64
|
+
window = QWidget()
|
|
65
|
+
widget = TransparentLineEdit()
|
|
66
|
+
window.setLayout(QVBoxLayout())
|
|
67
|
+
window.layout().addWidget(widget)
|
|
68
|
+
window.show()
|
|
69
|
+
sys.exit(app.exec())
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
from qfluentwidgets import (
|
|
2
|
+
TransparentDropDownPushButton,
|
|
3
|
+
Action,
|
|
4
|
+
FluentIcon,
|
|
5
|
+
CheckableMenu,
|
|
6
|
+
ColorDialog,
|
|
7
|
+
MenuIndicatorType,
|
|
8
|
+
)
|
|
9
|
+
from qfluentwidgets.common.icon import toQIcon
|
|
10
|
+
from PySide6.QtGui import QColor, QPixmap, QIcon
|
|
11
|
+
from PySide6.QtCore import Signal
|
|
12
|
+
from PySide6.QtWidgets import QApplication
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
TRADITIONAL_COLORS = {
|
|
16
|
+
"Black": QColor(45, 45, 45),
|
|
17
|
+
"White": QColor(255, 255, 255),
|
|
18
|
+
"Red": QColor(255, 0, 0),
|
|
19
|
+
"Green": QColor(0, 255, 0),
|
|
20
|
+
"Blue": QColor(0, 0, 255),
|
|
21
|
+
"Yellow": QColor(255, 255, 0),
|
|
22
|
+
"Cyan": QColor(0, 255, 255),
|
|
23
|
+
"Magenta": QColor(255, 0, 255),
|
|
24
|
+
"Gray": QColor(128, 128, 128),
|
|
25
|
+
"Dark gray": QColor(64, 64, 64),
|
|
26
|
+
"Light gray": QColor(192, 192, 192),
|
|
27
|
+
"Orange": QColor(255, 165, 0),
|
|
28
|
+
"Purple": QColor(128, 0, 128),
|
|
29
|
+
"Brown": QColor(165, 42, 42),
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
SCIENTIFIC_COLORS = {
|
|
33
|
+
"Black": QColor(0, 0, 0),
|
|
34
|
+
"Red": QColor("#FF1F5B"),
|
|
35
|
+
"Blue": QColor("#009ADE"),
|
|
36
|
+
"Yellow": QColor("#FFC61E"),
|
|
37
|
+
"Purple": QColor("#AF58BA"),
|
|
38
|
+
"Orange": QColor("#F28522"),
|
|
39
|
+
"Green": QColor("#00CD6C"),
|
|
40
|
+
"Brown": QColor("#A6761D"),
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
DEFAULT_LINE_WIDTHS = {
|
|
44
|
+
"0.25 pt": 0.25 * 2,
|
|
45
|
+
"0.5 pt": 0.5 * 2,
|
|
46
|
+
"0.75 pt": 0.75 * 2,
|
|
47
|
+
"1 pt": 1 * 2,
|
|
48
|
+
"1.5 pt": 1.5 * 2,
|
|
49
|
+
"2.25 pt": 2.25 * 2,
|
|
50
|
+
"3 pt": 3 * 2,
|
|
51
|
+
"4.5 pt": 4.5 * 2,
|
|
52
|
+
"6 pt": 6 * 2,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
DEFAULT_DASH_TYPE = {
|
|
56
|
+
"——————": [],
|
|
57
|
+
"—— —— ": [5, 5],
|
|
58
|
+
"⋅⋅⋅⋅⋅⋅⋅⋅": [1, 1],
|
|
59
|
+
"- ⋅ ": [3, 5, 1, 5],
|
|
60
|
+
"- ⋅ ⋅": [3, 5, 1, 5, 1, 5],
|
|
61
|
+
"———— ": [10, 3],
|
|
62
|
+
"—— ": [5, 10],
|
|
63
|
+
"- ⋅": [3, 10, 1, 10],
|
|
64
|
+
"- ⋅ ⋅": [3, 10, 1, 10, 1, 10],
|
|
65
|
+
"- ⋅ ⋅": [3, 1, 1, 1, 1, 1],
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class TransparentSelector(TransparentDropDownPushButton):
|
|
70
|
+
item_selected = Signal(str)
|
|
71
|
+
|
|
72
|
+
def __init__(self, items: dict, allow_custom=True, default_index=0, *args, **kwargs):
|
|
73
|
+
super().__init__(*args, **kwargs)
|
|
74
|
+
self.allow_custom = allow_custom
|
|
75
|
+
self.items = items
|
|
76
|
+
self.item_menu_actions = []
|
|
77
|
+
|
|
78
|
+
def generate_item_select_action(item_name):
|
|
79
|
+
item_action = Action(item_name)
|
|
80
|
+
item_action.setCheckable(True)
|
|
81
|
+
item_action.setChecked(False)
|
|
82
|
+
item_action.triggered.connect(lambda: self.on_item_menu_action_clicked(item_action))
|
|
83
|
+
return item_action
|
|
84
|
+
|
|
85
|
+
self.item_menu_actions = [
|
|
86
|
+
{"name": item_name, "value": value, "action": generate_item_select_action(item_name)}
|
|
87
|
+
for item_name, value in self.items.items()
|
|
88
|
+
]
|
|
89
|
+
if self.allow_custom:
|
|
90
|
+
self.customized_item = None
|
|
91
|
+
self.item_menu_actions.append(
|
|
92
|
+
{
|
|
93
|
+
"name": "customized",
|
|
94
|
+
"value": self.customized_item,
|
|
95
|
+
"action": generate_item_select_action("customized"),
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
self.item_menu_actions[default_index]["action"].setChecked(True)
|
|
99
|
+
self.current_item = self.item_menu_actions[default_index]["value"]
|
|
100
|
+
self.default_item = self.item_menu_actions[default_index]["value"]
|
|
101
|
+
self.item_menu = CheckableMenu(indicatorType=MenuIndicatorType.RADIO)
|
|
102
|
+
self.item_menu.addActions([item["action"] for item in self.item_menu_actions])
|
|
103
|
+
self.setMenu(self.item_menu)
|
|
104
|
+
self.setText(self.item_menu_actions[default_index]["action"].text())
|
|
105
|
+
|
|
106
|
+
def on_item_menu_action_clicked(self, action, emit=True):
|
|
107
|
+
if self.allow_custom and action.text() == "customized":
|
|
108
|
+
if self.get_custom_item():
|
|
109
|
+
self.current_item = self.customized_item
|
|
110
|
+
else:
|
|
111
|
+
self.set_item(self.current_item)
|
|
112
|
+
return False
|
|
113
|
+
else:
|
|
114
|
+
self.current_item = self.items[action.text()]
|
|
115
|
+
self.setText(action.text())
|
|
116
|
+
if emit:
|
|
117
|
+
self.item_selected.emit(action.text())
|
|
118
|
+
for other_action in self.item_menu_actions:
|
|
119
|
+
other_action["action"].setChecked(False)
|
|
120
|
+
action.setChecked(True)
|
|
121
|
+
return True
|
|
122
|
+
|
|
123
|
+
def set_item(self, item):
|
|
124
|
+
for action in self.item_menu_actions:
|
|
125
|
+
if action["value"] == item:
|
|
126
|
+
self.on_item_menu_action_clicked(action["action"], emit=False)
|
|
127
|
+
return 0
|
|
128
|
+
if self.allow_custom:
|
|
129
|
+
self.customized_item = item
|
|
130
|
+
self.current_item = item
|
|
131
|
+
action = self.item_menu_actions[-1]["action"]
|
|
132
|
+
self.setText(action.text())
|
|
133
|
+
for other_action in self.item_menu_actions:
|
|
134
|
+
other_action["action"].setChecked(False)
|
|
135
|
+
action.setChecked(True)
|
|
136
|
+
return 1
|
|
137
|
+
else:
|
|
138
|
+
raise ValueError("No such item in the menu")
|
|
139
|
+
|
|
140
|
+
def get_value(self, selected_text):
|
|
141
|
+
for action in self.item_menu_actions:
|
|
142
|
+
if action["name"] == selected_text:
|
|
143
|
+
return action["value"]
|
|
144
|
+
raise ValueError("No such item in the menu")
|
|
145
|
+
|
|
146
|
+
def get_custom_item(self):
|
|
147
|
+
return True
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class TransparentColorSelector(TransparentSelector):
|
|
151
|
+
def __init__(self, color_icon_width=24, color_icon_height=8, colors=SCIENTIFIC_COLORS, *args, **kwargs):
|
|
152
|
+
super().__init__(*args, items=colors, allow_custom=True, **kwargs)
|
|
153
|
+
self.color_icon_width = color_icon_width
|
|
154
|
+
self.color_icon_height = color_icon_height
|
|
155
|
+
for action in self.item_menu_actions[0:-1]:
|
|
156
|
+
action["action"].setIcon(self.__color_icon(colors[action["name"]]))
|
|
157
|
+
self.item_menu_actions[-1]["action"].setIcon(toQIcon(FluentIcon.PALETTE))
|
|
158
|
+
self.setIcon(self.__color_icon(self.current_item))
|
|
159
|
+
|
|
160
|
+
def on_item_menu_action_clicked(self, action, emit=True):
|
|
161
|
+
re = super().on_item_menu_action_clicked(action, emit)
|
|
162
|
+
if re:
|
|
163
|
+
self.setIcon(action.icon())
|
|
164
|
+
return re
|
|
165
|
+
|
|
166
|
+
def __color_icon(self, color):
|
|
167
|
+
pixmap = QPixmap(self.color_icon_width, self.color_icon_height)
|
|
168
|
+
pixmap.fill(color)
|
|
169
|
+
return QIcon(pixmap)
|
|
170
|
+
|
|
171
|
+
def set_item(self, item):
|
|
172
|
+
re = super().set_item(item)
|
|
173
|
+
if re == 1:
|
|
174
|
+
icon = toQIcon(self.__color_icon(item))
|
|
175
|
+
self.setIcon(icon)
|
|
176
|
+
self.item_menu_actions[-1]["action"].setIcon(icon)
|
|
177
|
+
return re
|
|
178
|
+
|
|
179
|
+
def get_custom_item(self):
|
|
180
|
+
if self.customized_item is not None:
|
|
181
|
+
default_color = self.customized_item
|
|
182
|
+
else:
|
|
183
|
+
default_color = self.current_item
|
|
184
|
+
w = ColorDialog(default_color, "Select Color", self.window())
|
|
185
|
+
if w.exec():
|
|
186
|
+
self.customized_item = w.color
|
|
187
|
+
self.item_menu_actions[-1]["value"] = self.customized_item
|
|
188
|
+
self.item_menu_actions[-1]["action"].setIcon(self.__color_icon(self.customized_item))
|
|
189
|
+
return True
|
|
190
|
+
else:
|
|
191
|
+
return False
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class TransparentLineWidthSelector(TransparentSelector):
|
|
195
|
+
def __init__(self, *args, **kwargs):
|
|
196
|
+
super().__init__(*args, items=DEFAULT_LINE_WIDTHS, default_index=3, allow_custom=False, **kwargs)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class TransparentDashTypeSelector(TransparentSelector):
|
|
200
|
+
def __init__(self, *args, **kwargs):
|
|
201
|
+
super().__init__(*args, items=DEFAULT_DASH_TYPE, default_index=0, allow_custom=False, **kwargs)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
if __name__ == "__main__":
|
|
205
|
+
app = QApplication(sys.argv)
|
|
206
|
+
widget = TransparentColorSelector()
|
|
207
|
+
widget.show()
|
|
208
|
+
sys.exit(app.exec())
|