[Needs Feedback] Add PyQt6. Remove PyQt4
- fully qualify enum values for Qt6 - add resource file per Qt version - TabWidget: use QPointF instead of QPoint for constructing mouse event Change-Id: I07da61c36c4228a60f6b5b9dacbead27c0a2409d Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30585 Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de> Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de> Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
This commit is contained in:
@ -40,7 +40,7 @@ def main(argv=None):
|
|||||||
app = QApplication(argv)
|
app = QApplication(argv)
|
||||||
window = MainWindow(args.file)
|
window = MainWindow(args.file)
|
||||||
window.show()
|
window.show()
|
||||||
return app.exec_()
|
return app.exec()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -72,7 +72,7 @@ def main(argv=None):
|
|||||||
app.aboutToQuit.connect(win._onQuit)
|
app.aboutToQuit.connect(win._onQuit)
|
||||||
win.show()
|
win.show()
|
||||||
|
|
||||||
return app.exec_()
|
return app.exec()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
File diff suppressed because it is too large
Load Diff
5930
frappy/gui/cfg_editor/icon_rc_qt6.py
Normal file
5930
frappy/gui/cfg_editor/icon_rc_qt6.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -132,12 +132,12 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
def close_tab(self, index):
|
def close_tab(self, index):
|
||||||
if self.tabWidget.widget(index).saved:
|
if self.tabWidget.widget(index).saved:
|
||||||
reply = QMessageBox.Close
|
reply = QMessageBox.StandardButton.Close
|
||||||
else:
|
else:
|
||||||
reply = self.show_save_message(self.tabWidget.tabText(index))
|
reply = self.show_save_message(self.tabWidget.tabText(index))
|
||||||
if reply == QMessageBox.Cancel:
|
if reply == QMessageBox.StandardButton.Cancel:
|
||||||
return
|
return
|
||||||
if reply == QMessageBox.Save:
|
if reply == QMessageBox.StandardButton.Save:
|
||||||
self.save_tab(index)
|
self.save_tab(index)
|
||||||
self.tabWidget.removeTab(index)
|
self.tabWidget.removeTab(index)
|
||||||
|
|
||||||
@ -155,11 +155,11 @@ class MainWindow(QMainWindow):
|
|||||||
reply = self.show_save_message()
|
reply = self.show_save_message()
|
||||||
break
|
break
|
||||||
if not reply:
|
if not reply:
|
||||||
reply = QMessageBox.Close
|
reply = QMessageBox.StandardButton.Close
|
||||||
if reply == QMessageBox.Cancel:
|
if reply == QMessageBox.StandardButton.Cancel:
|
||||||
event.ignore()
|
event.ignore()
|
||||||
return
|
return
|
||||||
if reply == QMessageBox.Save:
|
if reply == QMessageBox.StandardButton.Save:
|
||||||
for i in range(0, self.tabWidget.count()):
|
for i in range(0, self.tabWidget.count()):
|
||||||
self.save_tab(i)
|
self.save_tab(i)
|
||||||
event.accept()
|
event.accept()
|
||||||
@ -173,8 +173,10 @@ class MainWindow(QMainWindow):
|
|||||||
Your changes will be lost if you don't save them!
|
Your changes will be lost if you don't save them!
|
||||||
</p>
|
</p>
|
||||||
''' % file_name,
|
''' % file_name,
|
||||||
QMessageBox.Cancel | QMessageBox.Close |
|
QMessageBox.StandardButton.Cancel |
|
||||||
QMessageBox.Save, QMessageBox.Save)
|
QMessageBox.StandardButton.Close |
|
||||||
|
QMessageBox.StandardButton.Save,
|
||||||
|
QMessageBox.StandardButton.Save)
|
||||||
|
|
||||||
def new_node(self, name, file_path=None):
|
def new_node(self, name, file_path=None):
|
||||||
node = NodeDisplay(file_path)
|
node = NodeDisplay(file_path)
|
||||||
|
@ -33,7 +33,7 @@ class NodeDisplay(QWidget):
|
|||||||
self.created = self.tree_widget.set_file(file_path)
|
self.created = self.tree_widget.set_file(file_path)
|
||||||
self.tree_widget.save_status_changed.connect(self.change_save_status)
|
self.tree_widget.save_status_changed.connect(self.change_save_status)
|
||||||
self.tree_widget.currentItemChanged.connect(self.set_scroll_area)
|
self.tree_widget.currentItemChanged.connect(self.set_scroll_area)
|
||||||
self.scroll_area_layout.setAlignment(Qt.AlignTop)
|
self.scroll_area_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
|
||||||
self.set_scroll_area(self.tree_widget.get_selected_item(), None)
|
self.set_scroll_area(self.tree_widget.get_selected_item(), None)
|
||||||
self.splitter.setSizes([1, 1])
|
self.splitter.setSizes([1, 1])
|
||||||
|
|
||||||
@ -45,15 +45,15 @@ class NodeDisplay(QWidget):
|
|||||||
self.scroll_area_layout.addWidget(current.widget)
|
self.scroll_area_layout.addWidget(current.widget)
|
||||||
for index in range(0, current.childCount()):
|
for index in range(0, current.childCount()):
|
||||||
child_layout = QHBoxLayout()
|
child_layout = QHBoxLayout()
|
||||||
spacer = QSpacerItem(30, 0, QSizePolicy.Fixed,
|
spacer = QSpacerItem(30, 0, QSizePolicy.Policy.Fixed,
|
||||||
QSizePolicy.Minimum)
|
QSizePolicy.Policy.Minimum)
|
||||||
child_layout.addSpacerItem(spacer)
|
child_layout.addSpacerItem(spacer)
|
||||||
child_layout.addWidget(current.child(index).widget)
|
child_layout.addWidget(current.child(index).widget)
|
||||||
self.scroll_area_layout.addLayout(child_layout)
|
self.scroll_area_layout.addLayout(child_layout)
|
||||||
for sub_index in range(0, current.child(index).childCount()):
|
for sub_index in range(0, current.child(index).childCount()):
|
||||||
sub_child_layout = QHBoxLayout()
|
sub_child_layout = QHBoxLayout()
|
||||||
sub_spacer = QSpacerItem(60, 0, QSizePolicy.Fixed,
|
sub_spacer = QSpacerItem(60, 0, QSizePolicy.Policy.Fixed,
|
||||||
QSizePolicy.Minimum)
|
QSizePolicy.Policy.Minimum)
|
||||||
sub_child_layout.addSpacerItem(sub_spacer)
|
sub_child_layout.addSpacerItem(sub_spacer)
|
||||||
sub_child_layout.addWidget(
|
sub_child_layout.addWidget(
|
||||||
current.child(index).child(sub_index).widget)
|
current.child(index).child(sub_index).widget)
|
||||||
|
@ -56,7 +56,7 @@ class TreeWidgetItem(QTreeWidgetItem):
|
|||||||
else:
|
else:
|
||||||
setTreeIcon(self, 'empty.png')
|
setTreeIcon(self, 'empty.png')
|
||||||
font = QFont()
|
font = QFont()
|
||||||
font.setWeight(QFont.Bold)
|
font.setWeight(QFont.Weight.Bold)
|
||||||
self.setFont(0, font)
|
self.setFont(0, font)
|
||||||
self.setText(0, self.name)
|
self.setText(0, self.name)
|
||||||
self.duplicates = 0
|
self.duplicates = 0
|
||||||
@ -140,7 +140,8 @@ class ValueWidget(QWidget):
|
|||||||
self.edit_btn = QPushButton()
|
self.edit_btn = QPushButton()
|
||||||
setIcon(self.edit_btn, 'edit.png')
|
setIcon(self.edit_btn, 'edit.png')
|
||||||
self.edit_btn.setIconSize(QSize(18, 18))
|
self.edit_btn.setIconSize(QSize(18, 18))
|
||||||
self.edit_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
self.edit_btn.setSizePolicy(QSizePolicy.Policy.Fixed,
|
||||||
|
QSizePolicy.Policy.Fixed)
|
||||||
self.edit_btn.setFlat(True)
|
self.edit_btn.setFlat(True)
|
||||||
layout = QHBoxLayout()
|
layout = QHBoxLayout()
|
||||||
layout.addWidget(self.name_label)
|
layout.addWidget(self.name_label)
|
||||||
@ -215,7 +216,7 @@ class ChangeNameDialog(QDialog):
|
|||||||
self.name.textChanged.connect(self.check_input)
|
self.name.textChanged.connect(self.check_input)
|
||||||
|
|
||||||
def get_values(self):
|
def get_values(self):
|
||||||
if self.exec_() == QDialog.Accepted:
|
if self.exec() == QDialog.DialogCode.Accepted:
|
||||||
return self.name.text()
|
return self.name.text()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -49,12 +49,12 @@ def set_name_edit_style(invalid, name_edit, button_box=None):
|
|||||||
name_edit.setStyleSheet("color: red")
|
name_edit.setStyleSheet("color: red")
|
||||||
name_edit.setToolTip('Invalid name: name already taken')
|
name_edit.setToolTip('Invalid name: name already taken')
|
||||||
if button_box:
|
if button_box:
|
||||||
button_box.button(QDialogButtonBox.Ok).setEnabled(False)
|
button_box.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False)
|
||||||
else:
|
else:
|
||||||
name_edit.setStyleSheet("color: black")
|
name_edit.setStyleSheet("color: black")
|
||||||
name_edit.setToolTip('')
|
name_edit.setToolTip('')
|
||||||
if button_box:
|
if button_box:
|
||||||
button_box.button(QDialogButtonBox.Ok).setEnabled(True)
|
button_box.button(QDialogButtonBox.StandardButton.Ok).setEnabled(True)
|
||||||
|
|
||||||
|
|
||||||
def setTreeIcon(widget, icon_name, subdir='ui', icondir='icons'):
|
def setTreeIcon(widget, icon_name, subdir='ui', icondir='icons'):
|
||||||
@ -92,16 +92,16 @@ def get_file_paths(widget, open_file=True):
|
|||||||
dialog = QFileDialog(widget)
|
dialog = QFileDialog(widget)
|
||||||
if open_file:
|
if open_file:
|
||||||
title = 'Open file'
|
title = 'Open file'
|
||||||
dialog.setAcceptMode(QFileDialog.AcceptOpen)
|
dialog.setAcceptMode(QFileDialog.AcceptMode.AcceptOpen)
|
||||||
dialog.setFileMode(QFileDialog.ExistingFiles)
|
dialog.setFileMode(QFileDialog.FileMode.ExistingFiles)
|
||||||
else:
|
else:
|
||||||
title = 'Save file'
|
title = 'Save file'
|
||||||
dialog.setAcceptMode(QFileDialog.AcceptSave)
|
dialog.setAcceptMode(QFileDialog.AcceptMode.AcceptSave)
|
||||||
dialog.setFileMode(QFileDialog.AnyFile)
|
dialog.setFileMode(QFileDialog.FileMode.AnyFile)
|
||||||
dialog.setWindowTitle(title)
|
dialog.setWindowTitle(title)
|
||||||
dialog.setNameFilter('*.cfg')
|
dialog.setNameFilter('*.cfg')
|
||||||
dialog.setDefaultSuffix('.cfg')
|
dialog.setDefaultSuffix('.cfg')
|
||||||
dialog.exec_()
|
dialog.exec()
|
||||||
return dialog.selectedFiles()
|
return dialog.selectedFiles()
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,8 +51,8 @@ class TreeWidget(QTreeWidget):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.file_path = None
|
self.file_path = None
|
||||||
self.setIconSize(QSize(24, 24))
|
self.setIconSize(QSize(24, 24))
|
||||||
self.setSelectionMode(QTreeWidget.SingleSelection)
|
self.setSelectionMode(QTreeWidget.SelectionMode.SingleSelection)
|
||||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
||||||
self.context_pos = QPoint(0, 0)
|
self.context_pos = QPoint(0, 0)
|
||||||
self.menu = QMenu()
|
self.menu = QMenu()
|
||||||
self.context_actions = []
|
self.context_actions = []
|
||||||
@ -345,7 +345,8 @@ class AddDialog(QDialog):
|
|||||||
for i, name in enumerate(self.invalid_names):
|
for i, name in enumerate(self.invalid_names):
|
||||||
self.invalid_names[i] = name.lower()
|
self.invalid_names[i] = name.lower()
|
||||||
if kind in [NODE, MODULE, INTERFACE]:
|
if kind in [NODE, MODULE, INTERFACE]:
|
||||||
self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
|
self.button_box.button(
|
||||||
|
QDialogButtonBox.StandardButton.Ok).setEnabled(False)
|
||||||
self.name = QLineEdit()
|
self.name = QLineEdit()
|
||||||
# TODO: input mask
|
# TODO: input mask
|
||||||
self.name.textChanged.connect(self.check_input)
|
self.name.textChanged.connect(self.check_input)
|
||||||
@ -385,12 +386,15 @@ class AddDialog(QDialog):
|
|||||||
self.value.setFocus()
|
self.value.setFocus()
|
||||||
if self.add_layout.rowCount() == 2:
|
if self.add_layout.rowCount() == 2:
|
||||||
self.setTabOrder(self.name, self.value)
|
self.setTabOrder(self.name, self.value)
|
||||||
self.setTabOrder(self.value, self.button_box.button(QDialogButtonBox.Ok))
|
self.setTabOrder(self.value, self.button_box.button(
|
||||||
self.setTabOrder(self.button_box.button(QDialogButtonBox.Ok),
|
QDialogButtonBox.StandardButton.Ok))
|
||||||
self.button_box.button(QDialogButtonBox.Cancel))
|
self.setTabOrder(self.button_box.button(
|
||||||
|
QDialogButtonBox.StandardButton.Ok),
|
||||||
|
self.button_box.button(
|
||||||
|
QDialogButtonBox.StandardButton.Cancel))
|
||||||
|
|
||||||
def get_values(self):
|
def get_values(self):
|
||||||
if self.exec_() == QDialog.Accepted:
|
if self.exec() == QDialog.DialogCode.Accepted:
|
||||||
if self.kind in [NODE, MODULE, INTERFACE]:
|
if self.kind in [NODE, MODULE, INTERFACE]:
|
||||||
return [self.name.text(), self.get_value()]
|
return [self.name.text(), self.get_value()]
|
||||||
if self.kind in [PARAMETER, PROPERTY, COMMENT]:
|
if self.kind in [PARAMETER, PROPERTY, COMMENT]:
|
||||||
@ -406,7 +410,7 @@ class AddDialog(QDialog):
|
|||||||
class TabBar(QTabBar):
|
class TabBar(QTabBar):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
||||||
self.context_pos = QPoint(0, 0)
|
self.context_pos = QPoint(0, 0)
|
||||||
self.menu = QMenu()
|
self.menu = QMenu()
|
||||||
close = self.menu.addAction('&Close')
|
close = self.menu.addAction('&Close')
|
||||||
@ -417,7 +421,7 @@ class TabBar(QTabBar):
|
|||||||
self.setMovable(True)
|
self.setMovable(True)
|
||||||
|
|
||||||
def mouseReleaseEvent(self, event):
|
def mouseReleaseEvent(self, event):
|
||||||
if event.button() == Qt.MidButton:
|
if event.button() == Qt.MouseButton.MidButton:
|
||||||
self.close_tab_at_pos(event.pos())
|
self.close_tab_at_pos(event.pos())
|
||||||
QTabBar.mouseReleaseEvent(self, event)
|
QTabBar.mouseReleaseEvent(self, event)
|
||||||
|
|
||||||
|
@ -9,15 +9,17 @@ class CollapsibleWidget(QWidget):
|
|||||||
self.widget = QWidget()
|
self.widget = QWidget()
|
||||||
self.widgetContainer = QWidget()
|
self.widgetContainer = QWidget()
|
||||||
|
|
||||||
self.button.setArrowType(Qt.RightArrow)
|
self.button.setArrowType(Qt.ArrowType.RightArrow)
|
||||||
self.button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
self.button.setToolButtonStyle(
|
||||||
|
Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
|
||||||
self.button.setStyleSheet("QToolButton { border: none; }")
|
self.button.setStyleSheet("QToolButton { border: none; }")
|
||||||
self.button.setCheckable(True)
|
self.button.setCheckable(True)
|
||||||
self.button.toggled.connect(self._collapse)
|
self.button.toggled.connect(self._collapse)
|
||||||
|
|
||||||
line = QFrame()
|
line = QFrame()
|
||||||
line.setFrameShape(QFrame.HLine)
|
line.setFrameShape(QFrame.Shape.HLine)
|
||||||
line.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
|
line.setSizePolicy(QSizePolicy.Policy.Expanding,
|
||||||
|
QSizePolicy.Policy.Maximum)
|
||||||
|
|
||||||
l = QVBoxLayout()
|
l = QVBoxLayout()
|
||||||
l.setContentsMargins(0, 0, 0, 0)
|
l.setContentsMargins(0, 0, 0, 0)
|
||||||
@ -26,7 +28,7 @@ class CollapsibleWidget(QWidget):
|
|||||||
self.widgetContainer.setMaximumHeight(0)
|
self.widgetContainer.setMaximumHeight(0)
|
||||||
|
|
||||||
layout = QGridLayout()
|
layout = QGridLayout()
|
||||||
layout.addWidget(self.button, 0, 0, Qt.AlignLeft)
|
layout.addWidget(self.button, 0, 0, Qt.AlignmentFlag.AlignLeft)
|
||||||
layout.addWidget(line, 0, 1, 1, 1)
|
layout.addWidget(line, 0, 1, 1, 1)
|
||||||
layout.addWidget(self.widgetContainer, 1, 0, -1, -1)
|
layout.addWidget(self.widgetContainer, 1, 0, -1, -1)
|
||||||
layout.setContentsMargins(0, 6, 0, 0)
|
layout.setContentsMargins(0, 6, 0, 0)
|
||||||
@ -34,10 +36,10 @@ class CollapsibleWidget(QWidget):
|
|||||||
|
|
||||||
def _collapse(self, expand):
|
def _collapse(self, expand):
|
||||||
if expand:
|
if expand:
|
||||||
self.button.setArrowType(Qt.DownArrow)
|
self.button.setArrowType(Qt.ArrowType.DownArrow)
|
||||||
self.widgetContainer.setMaximumHeight(self.widget.maximumHeight())
|
self.widgetContainer.setMaximumHeight(self.widget.maximumHeight())
|
||||||
else:
|
else:
|
||||||
self.button.setArrowType(Qt.RightArrow)
|
self.button.setArrowType(Qt.ArrowType.RightArrow)
|
||||||
self.widgetContainer.setMaximumHeight(0)
|
self.widgetContainer.setMaximumHeight(0)
|
||||||
self.setMaximumHeight(self.button.maximumHeight())
|
self.setMaximumHeight(self.button.maximumHeight())
|
||||||
|
|
||||||
|
@ -58,8 +58,8 @@ class CommandDialog(QDialog):
|
|||||||
def get_value(self):
|
def get_value(self):
|
||||||
return True, self.widgets[0].get_value()
|
return True, self.widgets[0].get_value()
|
||||||
|
|
||||||
def exec_(self):
|
def exec(self):
|
||||||
if super().exec_():
|
if super().exec():
|
||||||
return self.get_value()
|
return self.get_value()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -69,14 +69,14 @@ def showCommandResultDialog(command, args, result, extras=''):
|
|||||||
args = '' if args is None else repr(args)
|
args = '' if args is None else repr(args)
|
||||||
m.setText('calling: %s(%s)\nyielded: %r\nqualifiers: %s' %
|
m.setText('calling: %s(%s)\nyielded: %r\nqualifiers: %s' %
|
||||||
(command, args, result, extras))
|
(command, args, result, extras))
|
||||||
m.exec_()
|
m.exec()
|
||||||
|
|
||||||
|
|
||||||
def showErrorDialog(command, args, error):
|
def showErrorDialog(command, args, error):
|
||||||
m = QMessageBox()
|
m = QMessageBox()
|
||||||
args = '' if args is None else repr(args)
|
args = '' if args is None else repr(args)
|
||||||
m.setText('calling: %s(%s)\nraised %r' % (command, args, error))
|
m.setText('calling: %s(%s)\nraised %r' % (command, args, error))
|
||||||
m.exec_()
|
m.exec()
|
||||||
|
|
||||||
|
|
||||||
class ParameterGroup(QWidget):
|
class ParameterGroup(QWidget):
|
||||||
@ -130,7 +130,7 @@ class CommandButton(QPushButton):
|
|||||||
self.setEnabled(False)
|
self.setEnabled(False)
|
||||||
if self._argintype:
|
if self._argintype:
|
||||||
dlg = CommandDialog(self._cmdname, self._argintype)
|
dlg = CommandDialog(self._cmdname, self._argintype)
|
||||||
args = dlg.exec_()
|
args = dlg.exec()
|
||||||
if args: # not 'Cancel' clicked
|
if args: # not 'Cancel' clicked
|
||||||
self._cb(self._cmdname, args[1])
|
self._cb(self._cmdname, args[1])
|
||||||
else:
|
else:
|
||||||
@ -276,12 +276,14 @@ class ModuleCtrl(QWidget):
|
|||||||
for prop in sorted(props):
|
for prop in sorted(props):
|
||||||
label = QLabel(prop + ':')
|
label = QLabel(prop + ':')
|
||||||
label.setFont(self._labelfont)
|
label.setFont(self._labelfont)
|
||||||
label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
|
label.setSizePolicy(QSizePolicy.Policy.Minimum,
|
||||||
|
QSizePolicy.Policy.Preferred)
|
||||||
|
|
||||||
# make 'display' label
|
# make 'display' label
|
||||||
view = QLabel(str(props[prop]))
|
view = QLabel(str(props[prop]))
|
||||||
view.setFont(self.font())
|
view.setFont(self.font())
|
||||||
view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
view.setSizePolicy(QSizePolicy.Policy.Expanding,
|
||||||
|
QSizePolicy.Policy.Preferred)
|
||||||
view.setWordWrap(True)
|
view.setWordWrap(True)
|
||||||
|
|
||||||
self.propertyGroupBox.layout().addWidget(label, row, 0)
|
self.propertyGroupBox.layout().addWidget(label, row, 0)
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
from frappy.gui.qt import QIcon, Qt, QTreeWidget, QTreeWidgetItem, pyqtSignal
|
from frappy.gui.qt import QIcon, Qt, QTreeWidget, QTreeWidgetItem, pyqtSignal
|
||||||
|
|
||||||
import frappy.gui.resources # pylint: disable=unused-import
|
|
||||||
|
|
||||||
|
|
||||||
class ParamItem(QTreeWidgetItem):
|
class ParamItem(QTreeWidgetItem):
|
||||||
def __init__(self, node, module, param):
|
def __init__(self, node, module, param):
|
||||||
@ -129,7 +127,7 @@ class ModuleOverview(QTreeWidget):
|
|||||||
|
|
||||||
self.itemExpanded.connect(self._resizeColumns)
|
self.itemExpanded.connect(self._resizeColumns)
|
||||||
self.itemCollapsed.connect(self._resizeColumns)
|
self.itemCollapsed.connect(self._resizeColumns)
|
||||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
||||||
# self.customContextMenuRequested.connect(self._contextMenu)
|
# self.customContextMenuRequested.connect(self._contextMenu)
|
||||||
|
|
||||||
self._node.newData.connect(self._updateValue)
|
self._node.newData.connect(self._updateValue)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
from frappy.gui.qt import QDialog, QIcon, QLabel, QLineEdit, QMessageBox, \
|
from frappy.gui.qt import QDialog, QIcon, QLabel, QLineEdit, QMessageBox, \
|
||||||
QPushButton, QToolButton, QWidget, pyqtSignal
|
QPushButton, QToolButton, QWidget, pyqtSignal
|
||||||
|
|
||||||
import frappy.gui.resources # pylint: disable=unused-import
|
|
||||||
from frappy.gui.util import Colors, loadUi
|
from frappy.gui.util import Colors, loadUi
|
||||||
from frappy.gui.valuewidgets import get_widget
|
from frappy.gui.valuewidgets import get_widget
|
||||||
|
|
||||||
@ -33,8 +32,8 @@ class CommandDialog(QDialog):
|
|||||||
def get_value(self):
|
def get_value(self):
|
||||||
return True, self.widgets[0].get_value()
|
return True, self.widgets[0].get_value()
|
||||||
|
|
||||||
def exec_(self):
|
def exec(self):
|
||||||
if super().exec_():
|
if super().exec():
|
||||||
return self.get_value()
|
return self.get_value()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -44,14 +43,14 @@ def showCommandResultDialog(command, args, result, extras=''):
|
|||||||
args = '' if args is None else repr(args)
|
args = '' if args is None else repr(args)
|
||||||
m.setText('calling: %s(%s)\nyielded: %r\nqualifiers: %s' %
|
m.setText('calling: %s(%s)\nyielded: %r\nqualifiers: %s' %
|
||||||
(command, args, result, extras))
|
(command, args, result, extras))
|
||||||
m.exec_()
|
m.exec()
|
||||||
|
|
||||||
|
|
||||||
def showErrorDialog(command, args, error):
|
def showErrorDialog(command, args, error):
|
||||||
m = QMessageBox()
|
m = QMessageBox()
|
||||||
args = '' if args is None else repr(args)
|
args = '' if args is None else repr(args)
|
||||||
m.setText('calling: %s(%s)\nraised %r' % (command, args, error))
|
m.setText('calling: %s(%s)\nraised %r' % (command, args, error))
|
||||||
m.exec_()
|
m.exec()
|
||||||
|
|
||||||
|
|
||||||
class CommandButton(QPushButton):
|
class CommandButton(QPushButton):
|
||||||
@ -72,7 +71,7 @@ class CommandButton(QPushButton):
|
|||||||
#self.setEnabled(False)
|
#self.setEnabled(False)
|
||||||
if self._argintype:
|
if self._argintype:
|
||||||
dlg = CommandDialog(self._cmdname, self._argintype)
|
dlg = CommandDialog(self._cmdname, self._argintype)
|
||||||
args = dlg.exec_()
|
args = dlg.exec()
|
||||||
if args: # not 'Cancel' clicked
|
if args: # not 'Cancel' clicked
|
||||||
self._cb(self._cmdname, args[1])
|
self._cb(self._cmdname, args[1])
|
||||||
else:
|
else:
|
||||||
|
@ -5,7 +5,6 @@ from frappy.gui.qt import QCursor, QFont, QFontMetrics, QGridLayout, QIcon, \
|
|||||||
QInputDialog, QLabel, QMenu, QPlainTextEdit, QTextCursor, QVBoxLayout, \
|
QInputDialog, QLabel, QMenu, QPlainTextEdit, QTextCursor, QVBoxLayout, \
|
||||||
QWidget, pyqtSignal, pyqtSlot, toHtmlEscaped
|
QWidget, pyqtSignal, pyqtSlot, toHtmlEscaped
|
||||||
|
|
||||||
import frappy.gui.resources # pylint: disable=unused-import
|
|
||||||
from frappy.errors import SECoPError
|
from frappy.errors import SECoPError
|
||||||
from frappy.gui.modulectrl import ModuleCtrl
|
from frappy.gui.modulectrl import ModuleCtrl
|
||||||
from frappy.gui.moduleoverview import ModuleOverview
|
from frappy.gui.moduleoverview import ModuleOverview
|
||||||
@ -78,7 +77,7 @@ class Console(QWidget):
|
|||||||
content += msg
|
content += msg
|
||||||
|
|
||||||
self.logTextBrowser.setHtml(content)
|
self.logTextBrowser.setHtml(content)
|
||||||
self.logTextBrowser.moveCursor(QTextCursor.End)
|
self.logTextBrowser.moveCursor(QTextCursor.MoveOperation.End)
|
||||||
|
|
||||||
def _getLogWidth(self):
|
def _getLogWidth(self):
|
||||||
fontMetrics = QFontMetrics(QFont('Monospace'))
|
fontMetrics = QFontMetrics(QFont('Monospace'))
|
||||||
@ -240,8 +239,8 @@ class NodeWidget(QWidget):
|
|||||||
opt_clear = menu.addAction('Clear Selection')
|
opt_clear = menu.addAction('Clear Selection')
|
||||||
opt_plot.triggered.connect(lambda: self._requestPlot(item))
|
opt_plot.triggered.connect(lambda: self._requestPlot(item))
|
||||||
opt_clear.triggered.connect(self.tree.clearTreeSelection)
|
opt_clear.triggered.connect(self.tree.clearTreeSelection)
|
||||||
#menu.exec_(self.mapToGlobal(pos))
|
#menu.exec(self.mapToGlobal(pos))
|
||||||
menu.exec_(QCursor.pos())
|
menu.exec(QCursor.pos())
|
||||||
|
|
||||||
def _requestPlot(self, item, plot=None):
|
def _requestPlot(self, item, plot=None):
|
||||||
module = item.module
|
module = item.module
|
||||||
@ -252,13 +251,14 @@ class NodeWidget(QWidget):
|
|||||||
plots = {'%s -> %s' % (m,p): (m,p) for (m,p) in self._activePlots}
|
plots = {'%s -> %s' % (m,p): (m,p) for (m,p) in self._activePlots}
|
||||||
dialog = QInputDialog()
|
dialog = QInputDialog()
|
||||||
#dialog.setInputMode()
|
#dialog.setInputMode()
|
||||||
dialog.setOption(QInputDialog.UseListViewForComboBoxItems)
|
dialog.setOption(
|
||||||
|
QInputDialog.InputDialogOption.UseListViewForComboBoxItems)
|
||||||
dialog.setComboBoxItems(plots.keys())
|
dialog.setComboBoxItems(plots.keys())
|
||||||
dialog.setTextValue(list(plots)[0])
|
dialog.setTextValue(list(plots)[0])
|
||||||
dialog.setWindowTitle('Plot %s with...' % param)
|
dialog.setWindowTitle('Plot %s with...' % param)
|
||||||
dialog.setLabelText('')
|
dialog.setLabelText('')
|
||||||
|
|
||||||
if dialog.exec_() == QInputDialog.Accepted:
|
if dialog.exec() == QInputDialog.DialogCode.Accepted:
|
||||||
item = dialog.textValue()
|
item = dialog.textValue()
|
||||||
self.plotParam(module, param, self._activePlots[plots[item]])
|
self.plotParam(module, param, self._activePlots[plots[item]])
|
||||||
|
|
||||||
|
@ -55,12 +55,14 @@ class ParameterView(QWidget):
|
|||||||
for prop in sorted(props):
|
for prop in sorted(props):
|
||||||
label = QLabel(prop + ':')
|
label = QLabel(prop + ':')
|
||||||
label.setFont(font)
|
label.setFont(font)
|
||||||
label.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
|
label.setSizePolicy(QSizePolicy.Policy.Minimum,
|
||||||
|
QSizePolicy.Policy.Preferred)
|
||||||
|
|
||||||
# make 'display' label
|
# make 'display' label
|
||||||
view = QLabel(str(props[prop]))
|
view = QLabel(str(props[prop]))
|
||||||
view.setFont(self.font())
|
view.setFont(self.font())
|
||||||
view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
view.setSizePolicy(QSizePolicy.Policy.Expanding,
|
||||||
|
QSizePolicy.Policy.Preferred)
|
||||||
view.setWordWrap(True)
|
view.setWordWrap(True)
|
||||||
|
|
||||||
self.propertyGroupBox.layout().addWidget(label, row, 0)
|
self.propertyGroupBox.layout().addWidget(label, row, 0)
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
|
from frappy.gui.qt import QLabel, Qt, QVBoxLayout, QWidget, pyqtSignal
|
||||||
|
|
||||||
|
from frappy.gui.util import Colors
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
@ -7,10 +11,6 @@ except ImportError:
|
|||||||
pg = None
|
pg = None
|
||||||
np = None
|
np = None
|
||||||
|
|
||||||
from frappy.gui.qt import QLabel, Qt, QVBoxLayout, QWidget, pyqtSignal
|
|
||||||
|
|
||||||
from frappy.gui.util import Colors
|
|
||||||
|
|
||||||
|
|
||||||
def getPlotWidget(parent):
|
def getPlotWidget(parent):
|
||||||
if pg:
|
if pg:
|
||||||
@ -32,7 +32,7 @@ class PlotPlaceHolderWidget(QWidget):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
l = QVBoxLayout()
|
l = QVBoxLayout()
|
||||||
label = QLabel("pyqtgraph is not installed!")
|
label = QLabel("pyqtgraph is not installed!")
|
||||||
label.setAlignment(Qt.AlignCenter)
|
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
l.addWidget(label)
|
l.addWidget(label)
|
||||||
self.setLayout(l)
|
self.setLayout(l)
|
||||||
self.setMinimumWidth(300)
|
self.setMinimumWidth(300)
|
||||||
|
@ -19,19 +19,38 @@
|
|||||||
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
|
||||||
#
|
#
|
||||||
# *****************************************************************************
|
# *****************************************************************************
|
||||||
"""Import needed stuff from PyQt4/PyQt5"""
|
"""Import needed stuff from PyQt5/PyQt6"""
|
||||||
|
|
||||||
# pylint: disable=unused-import
|
# pylint: disable=unused-import
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
|
||||||
# Do not abort on exceptions in signal handlers.
|
# Do not abort on exceptions in signal handlers.
|
||||||
# pylint: disable=unnecessary-lambda
|
# pylint: disable=unnecessary-lambda
|
||||||
sys.excepthook = lambda *args: sys.__excepthook__(*args)
|
sys.excepthook = lambda *args: sys.__excepthook__(*args)
|
||||||
|
|
||||||
from xml.sax.saxutils import escape as toHtmlEscaped
|
from xml.sax.saxutils import escape as toHtmlEscaped
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PyQt6 import uic
|
||||||
|
from PyQt6.QtCore import QByteArray, QEvent, QMimeData, QObject, QPoint, \
|
||||||
|
QPointF, QRectF, QSettings, QSize, Qt, pyqtSignal, pyqtSlot
|
||||||
|
from PyQt6.QtGui import QAction, QBrush, QColor, QCursor, QDrag, QFont, \
|
||||||
|
QFontMetrics, QIcon, QKeySequence, QMouseEvent, QPainter, QPalette, \
|
||||||
|
QPen, QPixmap, QPolygonF, QShortcut, QStandardItem, \
|
||||||
|
QStandardItemModel, QTextCursor
|
||||||
|
from PyQt6.QtWidgets import QApplication, QCheckBox, QComboBox, QDialog, \
|
||||||
|
QDialogButtonBox, QDoubleSpinBox, QFileDialog, QFrame, QGridLayout, \
|
||||||
|
QGroupBox, QHBoxLayout, QInputDialog, QLabel, QLineEdit, QMainWindow, \
|
||||||
|
QMenu, QMessageBox, QPlainTextEdit, QPushButton, QRadioButton, \
|
||||||
|
QScrollArea, QSizePolicy, QSpacerItem, QSpinBox, QStyle, \
|
||||||
|
QStyleOptionTab, QStylePainter, QTabBar, QTabWidget, QTextEdit, \
|
||||||
|
QToolButton, QTreeView, QTreeWidget, QTreeWidgetItem, QVBoxLayout, \
|
||||||
|
QWidget
|
||||||
|
|
||||||
|
import frappy.gui.cfg_editor.icon_rc_qt6
|
||||||
|
import frappy.gui.resources_qt6
|
||||||
|
|
||||||
|
except ImportError as e:
|
||||||
from PyQt5 import uic
|
from PyQt5 import uic
|
||||||
from PyQt5.QtCore import QByteArray, QEvent, QMimeData, QObject, QPoint, \
|
from PyQt5.QtCore import QByteArray, QEvent, QMimeData, QObject, QPoint, \
|
||||||
QPointF, QRectF, QSettings, QSize, Qt, pyqtSignal, pyqtSlot
|
QPointF, QRectF, QSettings, QSize, Qt, pyqtSignal, pyqtSlot
|
||||||
@ -49,22 +68,4 @@ try:
|
|||||||
QTreeWidgetItem, QVBoxLayout, QWidget
|
QTreeWidgetItem, QVBoxLayout, QWidget
|
||||||
|
|
||||||
import frappy.gui.cfg_editor.icon_rc_qt5
|
import frappy.gui.cfg_editor.icon_rc_qt5
|
||||||
|
import frappy.gui.resources_qt5
|
||||||
except ImportError:
|
|
||||||
from PyQt4 import uic
|
|
||||||
from PyQt4.QtCore import QObject, QPoint, QPointF, QRectF, QSize, Qt, \
|
|
||||||
pyqtSignal, pyqtSlot
|
|
||||||
from PyQt4.QtGui import QAbstractItemView, QAction, QApplication, QBrush, \
|
|
||||||
QCheckBox, QColor, QComboBox, QDialog, QDialogButtonBox, \
|
|
||||||
QDoubleSpinBox, QFileDialog, QFont, QFontMetrics, QFrame, \
|
|
||||||
QGridLayout, QGroupBox, QHBoxLayout, QIcon, QInputDialog, QLabel, \
|
|
||||||
QLineEdit, QMainWindow, QMenu, QMessageBox, QPainter, QPen, \
|
|
||||||
QPlainTextEdit, QPolygonF, QPushButton, QRadioButton, QScrollArea, \
|
|
||||||
QSizePolicy, QSpacerItem, QSpinBox, QStandardItem, \
|
|
||||||
QStandardItemModel, QTabBar, QTextCursor, QTextEdit, QTreeView, \
|
|
||||||
QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
|
|
||||||
|
|
||||||
import frappy.gui.cfg_editor.icon_rc_qt4
|
|
||||||
|
|
||||||
def toHtmlEscaped(s):
|
|
||||||
return Qt.escape(s)
|
|
||||||
|
2792
frappy/gui/resources_qt6.py
Normal file
2792
frappy/gui/resources_qt6.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -25,8 +25,9 @@
|
|||||||
"""Detachable TabWidget, taken from NICOS GUI TearOffTabBar."""
|
"""Detachable TabWidget, taken from NICOS GUI TearOffTabBar."""
|
||||||
|
|
||||||
from frappy.gui.qt import QApplication, QCursor, QDrag, QEvent, QMainWindow, \
|
from frappy.gui.qt import QApplication, QCursor, QDrag, QEvent, QMainWindow, \
|
||||||
QMimeData, QMouseEvent, QPixmap, QPoint, QSize, QStyle, QStyleOptionTab, \
|
QMimeData, QMouseEvent, QPixmap, QPoint, QPointF, QSize, QStyle, \
|
||||||
QStylePainter, Qt, QTabBar, QTabWidget, QWidget, pyqtSignal, pyqtSlot
|
QStyleOptionTab, QStylePainter, Qt, QTabBar, QTabWidget, QWidget, \
|
||||||
|
pyqtSignal, pyqtSlot
|
||||||
|
|
||||||
# def findTab(tab, w):
|
# def findTab(tab, w):
|
||||||
# widget = w
|
# widget = w
|
||||||
@ -55,33 +56,36 @@ class TearOffTabBar(QTabBar):
|
|||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QTabBar.__init__(self, parent)
|
QTabBar.__init__(self, parent)
|
||||||
self.setAcceptDrops(True)
|
self.setAcceptDrops(True)
|
||||||
self.setElideMode(Qt.ElideRight)
|
self.setElideMode(Qt.TextElideMode.ElideRight)
|
||||||
self.setSelectionBehaviorOnRemove(QTabBar.SelectLeftTab)
|
self.setSelectionBehaviorOnRemove(QTabBar.SelectionBehavior.SelectLeftTab)
|
||||||
self.setMovable(False)
|
self.setMovable(False)
|
||||||
self._dragInitiated = False
|
self._dragInitiated = False
|
||||||
self._dragDroppedPos = QPoint()
|
self._dragDroppedPos = QPoint()
|
||||||
self._dragStartPos = QPoint()
|
self._dragStartPos = QPoint()
|
||||||
|
|
||||||
def mousePressEvent(self, event):
|
def mousePressEvent(self, event):
|
||||||
if event.button() == Qt.LeftButton:
|
if event.button() == Qt.MouseButton.LeftButton:
|
||||||
self._dragStartPos = event.pos()
|
self._dragStartPos = event.pos()
|
||||||
self._dragInitiated = False
|
self._dragInitiated = False
|
||||||
self._dragDroppedPos = QPoint()
|
self._dragDroppedPos = QPoint()
|
||||||
QTabBar.mousePressEvent(self, event)
|
QTabBar.mousePressEvent(self, event)
|
||||||
|
|
||||||
def mouseMoveEvent(self, event):
|
def mouseMoveEvent(self, event):
|
||||||
if not event.buttons() & Qt.LeftButton:
|
if not event.buttons() & Qt.MouseButton.LeftButton:
|
||||||
return
|
return
|
||||||
if not self._dragStartPos.isNull() and \
|
if not self._dragStartPos.isNull() and \
|
||||||
self.tabAt(self._dragStartPos) != -1 and \
|
self.tabAt(self._dragStartPos) != -1 and \
|
||||||
(event.pos() - self._dragStartPos).manhattanLength() \
|
(event.pos() - self._dragStartPos).manhattanLength() \
|
||||||
< QApplication.startDragDistance():
|
< QApplication.startDragDistance():
|
||||||
self._dragInitiated = True
|
self._dragInitiated = True
|
||||||
if (event.buttons() == Qt.LeftButton) and self._dragInitiated and \
|
if (event.buttons() == Qt.MouseButton.LeftButton) and \
|
||||||
|
self._dragInitiated and \
|
||||||
not self.geometry().contains(event.pos()):
|
not self.geometry().contains(event.pos()):
|
||||||
finishMoveEvent = QMouseEvent(QEvent.MouseMove, event.pos(),
|
finishMoveEvent = QMouseEvent(QEvent.Type.MouseMove,
|
||||||
Qt.NoButton, Qt.NoButton,
|
QPointF(event.pos()),
|
||||||
Qt.NoModifier)
|
Qt.MouseButton.NoButton,
|
||||||
|
Qt.MouseButton.NoButton,
|
||||||
|
Qt.KeyboardModifier.NoModifier)
|
||||||
QTabBar.mouseMoveEvent(self, finishMoveEvent)
|
QTabBar.mouseMoveEvent(self, finishMoveEvent)
|
||||||
|
|
||||||
drag = QDrag(self)
|
drag = QDrag(self)
|
||||||
@ -90,17 +94,17 @@ class TearOffTabBar(QTabBar):
|
|||||||
drag.setMimeData(mimedata)
|
drag.setMimeData(mimedata)
|
||||||
|
|
||||||
pixmap = self.parentWidget().currentWidget().grab()
|
pixmap = self.parentWidget().currentWidget().grab()
|
||||||
pixmap = pixmap.scaled(640, 480, Qt.KeepAspectRatio)
|
pixmap = pixmap.scaled(640, 480, Qt.AspectRatioMode.KeepAspectRatio)
|
||||||
drag.setPixmap(pixmap)
|
drag.setPixmap(pixmap)
|
||||||
drag.setDragCursor(QPixmap(), Qt.LinkAction)
|
drag.setDragCursor(QPixmap(), Qt.DropAction.LinkAction)
|
||||||
|
|
||||||
dragged = drag.exec(Qt.MoveAction)
|
dragged = drag.exec(Qt.DropAction.MoveAction)
|
||||||
if dragged == Qt.IgnoreAction:
|
if dragged == Qt.DropAction.IgnoreAction:
|
||||||
# moved outside of tab widget
|
# moved outside of tab widget
|
||||||
event.accept()
|
event.accept()
|
||||||
self.tabDetached.emit(self.tabAt(self._dragStartPos),
|
self.tabDetached.emit(self.tabAt(self._dragStartPos),
|
||||||
QCursor.pos())
|
QCursor.pos())
|
||||||
elif dragged == Qt.MoveAction:
|
elif dragged == Qt.DropAction.MoveAction:
|
||||||
# moved inside of tab widget
|
# moved inside of tab widget
|
||||||
if not self._dragDroppedPos.isNull():
|
if not self._dragDroppedPos.isNull():
|
||||||
event.accept()
|
event.accept()
|
||||||
@ -137,10 +141,11 @@ class LeftTabBar(TearOffTabBar):
|
|||||||
self.initStyleOption(option, index)
|
self.initStyleOption(option, index)
|
||||||
tabRect = self.tabRect(index)
|
tabRect = self.tabRect(index)
|
||||||
tabRect.moveLeft(10)
|
tabRect.moveLeft(10)
|
||||||
painter.drawControl(QStyle.CE_TabBarTabShape, option)
|
painter.drawControl(QStyle.ControlElement.CE_TabBarTabShape, option)
|
||||||
text = self.tabText(index)
|
text = self.tabText(index)
|
||||||
painter.drawText(tabRect, Qt.AlignVCenter | Qt.TextDontClip |
|
painter.drawText(tabRect, Qt.AlignmentFlag.AlignVCenter |
|
||||||
Qt.TextShowMnemonic, text)
|
Qt.TextFlag.TextDontClip |
|
||||||
|
Qt.TextFlag.TextShowMnemonic, text)
|
||||||
|
|
||||||
def tabSizeHint(self, index):
|
def tabSizeHint(self, index):
|
||||||
fm = self.fontMetrics()
|
fm = self.fontMetrics()
|
||||||
@ -479,7 +484,7 @@ class DetachedWindow(QMainWindow):
|
|||||||
self.tabIdx = -1
|
self.tabIdx = -1
|
||||||
QMainWindow.__init__(self, parent)
|
QMainWindow.__init__(self, parent)
|
||||||
self.setWindowTitle(title)
|
self.setWindowTitle(title)
|
||||||
self.setWindowModality(Qt.NonModal)
|
self.setWindowModality(Qt.WindowModality.NonModal)
|
||||||
# self.sgroup = SettingGroup(title)
|
# self.sgroup = SettingGroup(title)
|
||||||
# with self.sgroup as settings:
|
# with self.sgroup as settings:
|
||||||
# loadBasicWindowSettings(self, settings)
|
# loadBasicWindowSettings(self, settings)
|
||||||
|
Reference in New Issue
Block a user