From 4108deb69a2e3f192353ef3e008966569255aa87 Mon Sep 17 00:00:00 2001 From: Dominik Demuth Date: Sun, 29 Sep 2024 17:21:40 +0000 Subject: [PATCH] run scripts run scripts Co-authored-by: Dominik Demuth Reviewed-on: https://gitea.pkm.physik.tu-darmstadt.de/IPKM/nmreval/pulls/291 --- src/gui_qt/_py/basewindow.py | 4 + src/gui_qt/_py/pokeentry.py | 116 ++++++------ src/gui_qt/_py/pokewindow.py | 30 ++- src/gui_qt/editors/__init__.py | 0 src/gui_qt/{lib => editors}/codeeditor.py | 12 +- src/gui_qt/editors/script_editor.py | 30 +++ .../{lib => editors}/usermodeleditor.py | 53 +++--- src/gui_qt/fit/fit_parameter.py | 9 +- src/gui_qt/fit/fitwindow.py | 10 +- src/gui_qt/fit/function_creation_dialog.py | 6 +- src/gui_qt/io/fcbatchreader.py | 1 - src/gui_qt/lib/logger.py | 2 +- src/gui_qt/lib/namespace.py | 3 + src/gui_qt/lib/pokemon.py | 79 +++++--- src/gui_qt/main/mainwindow.py | 15 +- src/gui_qt/main/management.py | 21 ++- src/nmreval/distributions/energy.py | 4 +- src/resources/_ui/basewindow.ui | 6 + src/resources/_ui/pokeentry.ui | 175 ++++++++++-------- src/resources/_ui/pokewindow.ui | 54 ++++-- 20 files changed, 401 insertions(+), 229 deletions(-) create mode 100644 src/gui_qt/editors/__init__.py rename src/gui_qt/{lib => editors}/codeeditor.py (96%) create mode 100644 src/gui_qt/editors/script_editor.py rename src/gui_qt/{lib => editors}/usermodeleditor.py (74%) diff --git a/src/gui_qt/_py/basewindow.py b/src/gui_qt/_py/basewindow.py index 8d23235..cca4f0f 100644 --- a/src/gui_qt/_py/basewindow.py +++ b/src/gui_qt/_py/basewindow.py @@ -372,6 +372,8 @@ class Ui_BaseWindow(object): self.action_cut_xaxis.setObjectName("action_cut_xaxis") self.action_cut_yaxis = QtWidgets.QAction(BaseWindow) self.action_cut_yaxis.setObjectName("action_cut_yaxis") + self.actionUse_script = QtWidgets.QAction(BaseWindow) + self.actionUse_script.setObjectName("actionUse_script") self.menuSave.addAction(self.actionSave) self.menuSave.addAction(self.actionExportGraphic) self.menuSave.addAction(self.action_save_fit_parameter) @@ -399,6 +401,7 @@ class Ui_BaseWindow(object): self.menuData.addAction(self.menuCut_to_visible_range.menuAction()) self.menuData.addSeparator() self.menuData.addAction(self.actionChange_datatypes) + self.menuData.addAction(self.actionUse_script) self.menuHelp.addAction(self.actionShow_error_log) self.menuHelp.addAction(self.actionUpdate) self.menuHelp.addAction(self.actionBugs) @@ -647,6 +650,7 @@ class Ui_BaseWindow(object): self.action_cut_xaxis.setToolTip(_translate("BaseWindow", "Remove data points outside visible x range.")) self.action_cut_yaxis.setText(_translate("BaseWindow", "y axis")) self.action_cut_yaxis.setToolTip(_translate("BaseWindow", "Remove data points outside visible y range. Uses real part of points.")) + self.actionUse_script.setText(_translate("BaseWindow", "Use script...")) from ..data.datawidget.datawidget import DataWidget from ..data.integral_widget import IntegralWidget from ..data.point_select import PointSelectWidget diff --git a/src/gui_qt/_py/pokeentry.py b/src/gui_qt/_py/pokeentry.py index c45dd6b..f12e3d9 100644 --- a/src/gui_qt/_py/pokeentry.py +++ b/src/gui_qt/_py/pokeentry.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'untitled2.ui' +# Form implementation generated from reading ui file './nmreval/src/resources/_ui/pokeentry.ui' # # Created by: PyQt5 UI code generator 5.15.10 # @@ -21,13 +21,26 @@ class Ui_Form(object): self.artwork_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) self.artwork_label.setObjectName("artwork_label") self.verticalLayout_4.addWidget(self.artwork_label) - self.gridLayout = QtWidgets.QGridLayout() - self.gridLayout.setVerticalSpacing(12) - self.gridLayout.setObjectName("gridLayout") + self.formLayout = QtWidgets.QFormLayout() + self.formLayout.setContentsMargins(3, 3, 3, 3) + self.formLayout.setVerticalSpacing(12) + self.formLayout.setObjectName("formLayout") + self.label = QtWidgets.QLabel(Form) + self.label.setObjectName("label") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label) + self.nationaldex_label = QtWidgets.QLabel(Form) + self.nationaldex_label.setObjectName("nationaldex_label") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.nationaldex_label) + self.label_1 = QtWidgets.QLabel(Form) + self.label_1.setObjectName("label_1") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_1) + self.species_label = QtWidgets.QLabel(Form) + self.species_label.setObjectName("species_label") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.species_label) self.label_4 = QtWidgets.QLabel(Form) self.label_4.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) self.label_4.setObjectName("label_4") - self.gridLayout.addWidget(self.label_4, 2, 0, 1, 1) + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_4) self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") self.type1_label = QtWidgets.QLabel(Form) @@ -36,24 +49,11 @@ class Ui_Form(object): self.type2_label = QtWidgets.QLabel(Form) self.type2_label.setObjectName("type2_label") self.verticalLayout_2.addWidget(self.type2_label) - self.gridLayout.addLayout(self.verticalLayout_2, 2, 1, 1, 1) - self.label_3 = QtWidgets.QLabel(Form) - self.label_3.setObjectName("label_3") - self.gridLayout.addWidget(self.label_3, 5, 0, 1, 1) - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout.addItem(spacerItem, 7, 0, 1, 1) - self.label_2 = QtWidgets.QLabel(Form) - self.label_2.setObjectName("label_2") - self.gridLayout.addWidget(self.label_2, 4, 0, 1, 1) - self.height_label = QtWidgets.QLabel(Form) - self.height_label.setObjectName("height_label") - self.gridLayout.addWidget(self.height_label, 4, 1, 1, 1) - self.weight_label = QtWidgets.QLabel(Form) - self.weight_label.setObjectName("weight_label") - self.gridLayout.addWidget(self.weight_label, 5, 1, 1, 1) - self.label_1 = QtWidgets.QLabel(Form) - self.label_1.setObjectName("label_1") - self.gridLayout.addWidget(self.label_1, 1, 0, 1, 1) + self.formLayout.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.verticalLayout_2) + self.label_5 = QtWidgets.QLabel(Form) + self.label_5.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.label_5.setObjectName("label_5") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_5) self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.ability1_label = QtWidgets.QLabel(Form) @@ -65,24 +65,23 @@ class Ui_Form(object): self.ability3_label = QtWidgets.QLabel(Form) self.ability3_label.setObjectName("ability3_label") self.verticalLayout.addWidget(self.ability3_label) - self.gridLayout.addLayout(self.verticalLayout, 3, 1, 1, 1) - self.species_label = QtWidgets.QLabel(Form) - self.species_label.setObjectName("species_label") - self.gridLayout.addWidget(self.species_label, 1, 1, 1, 1) - self.label_5 = QtWidgets.QLabel(Form) - self.label_5.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) - self.label_5.setObjectName("label_5") - self.gridLayout.addWidget(self.label_5, 3, 0, 1, 1) + self.formLayout.setLayout(3, QtWidgets.QFormLayout.FieldRole, self.verticalLayout) + self.label_2 = QtWidgets.QLabel(Form) + self.label_2.setObjectName("label_2") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_2) + self.height_label = QtWidgets.QLabel(Form) + self.height_label.setObjectName("height_label") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.height_label) + self.label_3 = QtWidgets.QLabel(Form) + self.label_3.setObjectName("label_3") + self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_3) + self.weight_label = QtWidgets.QLabel(Form) + self.weight_label.setObjectName("weight_label") + self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.weight_label) self.gender_label = QtWidgets.QLabel(Form) self.gender_label.setObjectName("gender_label") - self.gridLayout.addWidget(self.gender_label, 6, 0, 1, 2) - self.label = QtWidgets.QLabel(Form) - self.label.setObjectName("label") - self.gridLayout.addWidget(self.label, 0, 0, 1, 1) - self.nationaldex_label = QtWidgets.QLabel(Form) - self.nationaldex_label.setObjectName("nationaldex_label") - self.gridLayout.addWidget(self.nationaldex_label, 0, 1, 1, 1) - self.verticalLayout_4.addLayout(self.gridLayout) + self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.gender_label) + self.verticalLayout_4.addLayout(self.formLayout) self.groupBox = QtWidgets.QGroupBox(Form) self.groupBox.setFlat(True) self.groupBox.setObjectName("groupBox") @@ -206,13 +205,21 @@ class Ui_Form(object): self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox_2) self.verticalLayout_3.setContentsMargins(3, 3, 3, 3) self.verticalLayout_3.setObjectName("verticalLayout_3") - self.evolution_bar = QtWidgets.QLabel(self.groupBox_2) - self.evolution_bar.setFrameShape(QtWidgets.QFrame.NoFrame) - self.evolution_bar.setFrameShadow(QtWidgets.QFrame.Raised) - self.evolution_bar.setLineWidth(0) - self.evolution_bar.setObjectName("evolution_bar") - self.verticalLayout_3.addWidget(self.evolution_bar) + self.tableWidget = QtWidgets.QTableWidget(self.groupBox_2) + self.tableWidget.setStyleSheet("background-color: transparent;") + self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.tableWidget.setShowGrid(False) + self.tableWidget.setGridStyle(QtCore.Qt.NoPen) + self.tableWidget.setWordWrap(False) + self.tableWidget.setObjectName("tableWidget") + self.tableWidget.setColumnCount(0) + self.tableWidget.setRowCount(0) + self.tableWidget.horizontalHeader().setVisible(False) + self.tableWidget.verticalHeader().setVisible(False) + self.verticalLayout_3.addWidget(self.tableWidget) self.verticalLayout_4.addWidget(self.groupBox_2) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_4.addItem(spacerItem) self.retranslateUi(Form) QtCore.QMetaObject.connectSlotsByName(Form) @@ -221,22 +228,22 @@ class Ui_Form(object): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "Form")) self.artwork_label.setText(_translate("Form", "TextLabel")) + self.label.setText(_translate("Form", "National No.")) + self.nationaldex_label.setText(_translate("Form", "TextLabel")) + self.label_1.setText(_translate("Form", "Species")) + self.species_label.setText(_translate("Form", "TextLabel")) self.label_4.setText(_translate("Form", "Type")) self.type1_label.setText(_translate("Form", "TextLabel")) self.type2_label.setText(_translate("Form", "TextLabel")) - self.label_3.setText(_translate("Form", "Weight")) - self.label_2.setText(_translate("Form", "Height")) - self.height_label.setText(_translate("Form", "0.0 m")) - self.weight_label.setText(_translate("Form", "0.0 kg")) - self.label_1.setText(_translate("Form", "Species")) + self.label_5.setText(_translate("Form", "Abilities")) self.ability1_label.setText(_translate("Form", "TextLabel")) self.ability2_label.setText(_translate("Form", "TextLabel")) self.ability3_label.setText(_translate("Form", "TextLabel")) - self.species_label.setText(_translate("Form", "TextLabel")) - self.label_5.setText(_translate("Form", "Abilities")) + self.label_2.setText(_translate("Form", "Height")) + self.height_label.setText(_translate("Form", "0.0 m")) + self.label_3.setText(_translate("Form", "Weight")) + self.weight_label.setText(_translate("Form", "0.0 kg")) self.gender_label.setText(_translate("Form", "TextLabel")) - self.label.setText(_translate("Form", "National No.")) - self.nationaldex_label.setText(_translate("Form", "TextLabel")) self.groupBox.setTitle(_translate("Form", "Stats")) self.spec_attack_bar.setFormat(_translate("Form", "%v")) self.label_8.setText(_translate("Form", "Special Attack")) @@ -251,4 +258,3 @@ class Ui_Form(object): self.label_7.setText(_translate("Form", "Attack")) self.label_9.setText(_translate("Form", "Defense")) self.groupBox_2.setTitle(_translate("Form", "Evolution chain")) - self.evolution_bar.setText(_translate("Form", "TextLabel")) diff --git a/src/gui_qt/_py/pokewindow.py b/src/gui_qt/_py/pokewindow.py index 069b9d6..2cca68b 100644 --- a/src/gui_qt/_py/pokewindow.py +++ b/src/gui_qt/_py/pokewindow.py @@ -14,15 +14,29 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(1526, 991) + Dialog.resize(1687, 991) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") - self.comboBox = QtWidgets.QComboBox(Dialog) - self.comboBox.setObjectName("comboBox") - self.gridLayout.addWidget(self.comboBox, 0, 1, 1, 1) + self.pushButton = QtWidgets.QPushButton(Dialog) + self.pushButton.setObjectName("pushButton") + self.gridLayout.addWidget(self.pushButton, 0, 2, 1, 1) self.comboBox_2 = QtWidgets.QComboBox(Dialog) self.comboBox_2.setObjectName("comboBox_2") self.gridLayout.addWidget(self.comboBox_2, 0, 0, 1, 1) + self.comboBox = QtWidgets.QComboBox(Dialog) + self.comboBox.setObjectName("comboBox") + self.gridLayout.addWidget(self.comboBox, 0, 1, 1, 1) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem, 0, 4, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth()) + self.buttonBox.setSizePolicy(sizePolicy) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 0, 3, 1, 1) self.splitter = QtWidgets.QSplitter(Dialog) self.splitter.setOrientation(QtCore.Qt.Horizontal) self.splitter.setObjectName("splitter") @@ -66,12 +80,9 @@ class Ui_Dialog(object): self.tableWidget_2.horizontalHeader().setStretchLastSection(False) self.tableWidget_2.verticalHeader().setVisible(False) self.tabWidget = QtWidgets.QTabWidget(self.splitter) + self.tabWidget.setMinimumSize(QtCore.QSize(418, 0)) self.tabWidget.setObjectName("tabWidget") - self.gridLayout.addWidget(self.splitter, 2, 0, 1, 2) - self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close) - self.buttonBox.setObjectName("buttonBox") - self.gridLayout.addWidget(self.buttonBox, 3, 0, 1, 2) + self.gridLayout.addWidget(self.splitter, 1, 0, 1, 5) self.retranslateUi(Dialog) self.tabWidget.setCurrentIndex(-1) @@ -81,6 +92,7 @@ class Ui_Dialog(object): def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Gotta catch \'em all!")) + self.pushButton.setText(_translate("Dialog", "Random")) self.tableWidget_2.setSortingEnabled(True) item = self.tableWidget_2.horizontalHeaderItem(0) item.setText(_translate("Dialog", "#")) diff --git a/src/gui_qt/editors/__init__.py b/src/gui_qt/editors/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/gui_qt/lib/codeeditor.py b/src/gui_qt/editors/codeeditor.py similarity index 96% rename from src/gui_qt/lib/codeeditor.py rename to src/gui_qt/editors/codeeditor.py index f910b26..a90840f 100644 --- a/src/gui_qt/lib/codeeditor.py +++ b/src/gui_qt/editors/codeeditor.py @@ -187,10 +187,10 @@ class CodeEditor(QtWidgets.QPlainTextEdit): self.highlight = PythonHighlighter(self.document()) def keyPressEvent(self, evt): - if evt.key() == QtCore.Qt.Key_Tab: + if evt.key() == QtCore.Qt.Key.Key_Tab: # use spaces instead of tab self.insertPlainText(' '*4) - elif evt.key() == QtCore.Qt.Key_Insert: + elif evt.key() == QtCore.Qt.Key.Key_Insert: self.setOverwriteMode(not self.overwriteMode()) else: super().keyPressEvent(evt) @@ -225,7 +225,7 @@ class CodeEditor(QtWidgets.QPlainTextEdit): def paintevent_linenumber(self, evt): painter = QtGui.QPainter(self.current_linenumber) - painter.fillRect(evt.rect(), QtCore.Qt.lightGray) + painter.fillRect(evt.rect(), QtCore.Qt.GlobalColor.lightGray) block = self.firstVisibleBlock() block_number = block.blockNumber() @@ -237,9 +237,9 @@ class CodeEditor(QtWidgets.QPlainTextEdit): while block.isValid() and (top <= evt.rect().bottom()): if block.isVisible() and (bottom >= evt.rect().top()): number = str(block_number + 1) - painter.setPen(QtCore.Qt.black) + painter.setPen(QtCore.Qt.GlobalColor.black) painter.drawText(0, int(top), self.current_linenumber.width() - 3, height, - QtCore.Qt.AlignRight, number) + QtCore.Qt.AlignmentFlag.AlignRight, number) block = block.next() top = bottom @@ -252,7 +252,7 @@ class CodeEditor(QtWidgets.QPlainTextEdit): if not self.isReadOnly(): selection = QtWidgets.QTextEdit.ExtraSelection() - line_color = QtGui.QColor(QtCore.Qt.yellow).lighter(180) + line_color = QtGui.QColor(QtCore.Qt.GlobalColor.yellow).lighter(180) selection.format.setBackground(line_color) selection.format.setProperty(QtGui.QTextFormat.FullWidthSelection, True) diff --git a/src/gui_qt/editors/script_editor.py b/src/gui_qt/editors/script_editor.py new file mode 100644 index 0000000..ae3d175 --- /dev/null +++ b/src/gui_qt/editors/script_editor.py @@ -0,0 +1,30 @@ +from __future__ import annotations + +from pathlib import Path + +from .usermodeleditor import QUsermodelEditor +from ..Qt import QtWidgets, QtCore, QtGui + + +class QEditor(QUsermodelEditor): + runSignal = QtCore.pyqtSignal(str) + + def __init__(self, path: str | Path = None, parent=None): + super().__init__(path, parent=parent) + + self.add_run_button() + + def add_run_button(self): + self.disclaimer = QtWidgets.QLabel("This is work in progress and less than perfect :(") + self.disclaimer.setStyleSheet('QLabel {color: rgb(255, 0, 0); font-weight: bold; font-size: 2.5em;};') + self.centralwidget.layout().insertWidget(0, self.disclaimer) + + self.run_button = QtWidgets.QPushButton("Run") + self.centralwidget.layout().addWidget(self.run_button) + + self.run_button.clicked.connect(self.start_script) + + @QtCore.pyqtSlot() + def start_script(self): + self.runSignal.emit(self.edit_field.toPlainText()) + diff --git a/src/gui_qt/lib/usermodeleditor.py b/src/gui_qt/editors/usermodeleditor.py similarity index 74% rename from src/gui_qt/lib/usermodeleditor.py rename to src/gui_qt/editors/usermodeleditor.py index d9e5761..3cc1dbc 100644 --- a/src/gui_qt/lib/usermodeleditor.py +++ b/src/gui_qt/editors/usermodeleditor.py @@ -3,7 +3,7 @@ from __future__ import annotations from pathlib import Path from ..Qt import QtWidgets, QtCore, QtGui -from ..lib.codeeditor import EditorWidget +from .codeeditor import EditorWidget class QUsermodelEditor(QtWidgets.QMainWindow): @@ -50,18 +50,20 @@ class QUsermodelEditor(QtWidgets.QMainWindow): self.menuFile.addAction('Close', self.close, QtGui.QKeySequence.Quit) self.resize(800, 600) - self.setGeometry(QtWidgets.QStyle.alignedRect( - QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter, - self.size(), QtWidgets.qApp.desktop().availableGeometry() - )) + self.setGeometry( + QtWidgets.QStyle.alignedRect( + QtCore.Qt.LayoutDirection.LeftToRight, + QtCore.Qt.AlignmentFlag.AlignCenter, + self.size(), + QtWidgets.qApp.desktop().availableGeometry() + ) + ) - @property def is_modified(self): - return self.edit_field.document().isModified() + return self.edit_field.editor.document().isModified() - @is_modified.setter - def is_modified(self, val: bool): - self.edit_field.document().setModified(val) + def set_modified(self, val: bool): + self.edit_field.editor.document().setModified(val) @QtCore.pyqtSlot() def open_file(self): @@ -75,17 +77,22 @@ class QUsermodelEditor(QtWidgets.QMainWindow): def read_file(self, fname: str | Path): self.set_fname_opts(fname) - with self.fname.open('r') as f: - self.edit_field.setPlainText(f.read()) + if self.fname is not None: + with self.fname.open('r') as f: + self.edit_field.setPlainText(f.read()) def set_fname_opts(self, fname: str | Path): - self.fname = Path(fname) - self._dir = self.fname.parent - self.setWindowTitle('Edit ' + str(fname)) + fname = Path(fname) + if fname.is_file(): + self.fname = Path(fname) + self._dir = self.fname.parent + self.setWindowTitle('Edit ' + str(fname)) + elif fname.is_dir(): + self._dir = fname + - @property def changes_saved(self) -> bool: - if not self.is_modified: + if not self.is_modified(): return True ret = QtWidgets.QMessageBox.question(self, 'Time to think', @@ -97,9 +104,9 @@ class QUsermodelEditor(QtWidgets.QMainWindow): self.save_file() if ret == QtWidgets.QMessageBox.No: - self.is_modified = False + self.set_modified(False) - return not self.is_modified + return not self.is_modified() @QtCore.pyqtSlot() def save_file(self): @@ -111,9 +118,9 @@ class QUsermodelEditor(QtWidgets.QMainWindow): self.set_fname_opts(outfile) - self.is_modified = False + self.set_modified(False) - return self.is_modified + return self.is_modified() @QtCore.pyqtSlot() def overwrite_file(self): @@ -123,10 +130,10 @@ class QUsermodelEditor(QtWidgets.QMainWindow): self.modelsChanged.emit() - self.is_modified = False + self.set_modified(False) def closeEvent(self, evt: QtGui.QCloseEvent): - if not self.changes_saved: + if not self.changes_saved(): evt.ignore() else: super().closeEvent(evt) diff --git a/src/gui_qt/fit/fit_parameter.py b/src/gui_qt/fit/fit_parameter.py index e470691..756fb3f 100644 --- a/src/gui_qt/fit/fit_parameter.py +++ b/src/gui_qt/fit/fit_parameter.py @@ -12,12 +12,13 @@ from ..lib.forms import SelectionWidget class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit): value_requested = QtCore.pyqtSignal(int) - def __init__(self, parent=None): + def __init__(self, func_id: int, parent=None): super().__init__(parent=parent) self.setupUi(self) self.func = None self.func_idx = None + self.func_id = func_id self.max_width = QtCore.QSize(0, 0) self.global_parameter = [] self.data_parameter = [] @@ -301,8 +302,10 @@ class ParameterSingleWidget(QtWidgets.QWidget): self.name = name self.parametername.setText(convert(name)) - self.parametername.setToolTip('If this is bold then this parameter is only for this data. ' - 'Otherwise, the general parameter is used and displayed') + self.parametername.setToolTip( + 'If this is bold then this parameter is only for this data. ' + 'Otherwise, the general parameter is used and displayed' + ) # self.value_line.setValidator(QtGui.QDoubleValidator()) self.value_line.textChanged.connect(lambda: self.valueChanged.emit(self.value) if self.value is not None else 0) diff --git a/src/gui_qt/fit/fitwindow.py b/src/gui_qt/fit/fitwindow.py index 6700493..9aeaed3 100644 --- a/src/gui_qt/fit/fitwindow.py +++ b/src/gui_qt/fit/fitwindow.py @@ -77,8 +77,12 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog): """ w = self.param_widgets[idx] self.stackedWidget.removeWidget(w) + w.setParent(None) w.deleteLater() del self.param_widgets[idx] + _, func_id = self.functionwidget.get_selected() + + self.get_functions() self._current_function = None if len(self.param_widgets) == 0: @@ -104,7 +108,7 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog): if function is None: return - dialog = QFitParameterWidget(self.stackedWidget) + dialog = QFitParameterWidget(function_id, self.stackedWidget) data_names = self.data_table.data_list(include_name=True) dialog.set_function(function, function_idx) @@ -206,9 +210,7 @@ class QFitDialog(QtWidgets.QWidget, Ui_FitDialog): for m in self.models[model_id]: func_id = m['cnt'] - self.stackedWidget.removeWidget(self.param_widgets[func_id]) - - self.param_widgets.pop(func_id) + self.remove_function(func_id) self._complex.pop(model_id) self._func_list.pop(model_id) diff --git a/src/gui_qt/fit/function_creation_dialog.py b/src/gui_qt/fit/function_creation_dialog.py index 25562cd..caf7d42 100644 --- a/src/gui_qt/fit/function_creation_dialog.py +++ b/src/gui_qt/fit/function_creation_dialog.py @@ -8,9 +8,9 @@ from typing import Any import numpy as np -from gui_qt.Qt import QtCore, QtWidgets, QtGui -from gui_qt._py.fitcreationdialog import Ui_Dialog -from gui_qt.lib.namespace import QNamespaceWidget +from ..Qt import QtCore, QtWidgets, QtGui +from .._py.fitcreationdialog import Ui_Dialog +from ..editors.namespace import QNamespaceWidget __all__ = ['QUserFitCreator'] diff --git a/src/gui_qt/io/fcbatchreader.py b/src/gui_qt/io/fcbatchreader.py index a4444e6..c62acb2 100644 --- a/src/gui_qt/io/fcbatchreader.py +++ b/src/gui_qt/io/fcbatchreader.py @@ -88,7 +88,6 @@ class QFCReader(QtWidgets.QDialog, Ui_FCEval_dialog): def accept(self): items = [self.listWidget.item(i).text() for i in range(self.listWidget.count())] - print(items) if items: with busy_cursor(): self.read(items) diff --git a/src/gui_qt/lib/logger.py b/src/gui_qt/lib/logger.py index 346b638..e495ee1 100644 --- a/src/gui_qt/lib/logger.py +++ b/src/gui_qt/lib/logger.py @@ -3,7 +3,7 @@ from pathlib import Path from PyQt5 import QtWidgets -from .codeeditor import _make_textformats +from ..editors.codeeditor import _make_textformats from ..Qt import QtWidgets, QtCore, QtGui from nmreval.configs import config_paths diff --git a/src/gui_qt/lib/namespace.py b/src/gui_qt/lib/namespace.py index ae783ba..e164cd3 100644 --- a/src/gui_qt/lib/namespace.py +++ b/src/gui_qt/lib/namespace.py @@ -4,6 +4,8 @@ from collections import namedtuple import numpy as np +import nmreval + from nmreval import models from nmreval.configs import config_paths from nmreval.lib.importer import find_models, import_ @@ -28,6 +30,7 @@ class Namespace: 'y_err': (None, 'y error values'), 'fit': (None, 'dictionary of fit parameter', 'fit["PIKA"]'), 'np': (np, 'numpy module'), + 'nmreval': (nmreval, 'built-in classes and stuff') }, parents=('Basic', 'General'), ) diff --git a/src/gui_qt/lib/pokemon.py b/src/gui_qt/lib/pokemon.py index 15df4b7..b538acd 100644 --- a/src/gui_qt/lib/pokemon.py +++ b/src/gui_qt/lib/pokemon.py @@ -3,8 +3,10 @@ import urllib.request from functools import cache from PyQt5 import QtWidgets, QtGui, QtCore -from .._py.pokewindow import Ui_Dialog -from .._py.pokeentry import Ui_Form +from numpy.random import randint + +from gui_qt._py.pokewindow import Ui_Dialog +from gui_qt._py.pokeentry import Ui_Form def get_connection(db): @@ -37,6 +39,8 @@ class QPoke(QtWidgets.QDialog, Ui_Dialog): self.comboBox_2.currentIndexChanged.connect(self.collect_pokemon) self.comboBox.currentIndexChanged.connect(self.collect_pokemon) + self.pushButton.clicked.connect(self.randomize) + self.collect_pokemon() def _fetch_names(self): @@ -149,12 +153,15 @@ class QPoke(QtWidgets.QDialog, Ui_Dialog): self.tableWidget_2.clearContents() self.tableWidget_2.setRowCount(0) + self.tableWidget_2.setSortingEnabled(False) + for entry in result: row = self.tableWidget_2.rowCount() self.tableWidget_2.setRowCount(row+1) item = QtWidgets.QTableWidgetItem(f"{entry['entry_number']:04d}") item.setData(QtCore.Qt.ItemDataRole.UserRole, entry['species_id']) + item.setData(QtCore.Qt.ItemDataRole.UserRole+1, entry['pokemon_id']) self.tableWidget_2.setItem(row, 0, item) name_en = entry['name_en'] @@ -181,7 +188,7 @@ class QPoke(QtWidgets.QDialog, Ui_Dialog): type_en.append(t_en) type_de.append(t_de) - item = QtWidgets.QTableWidgetItem('\n'.join(type_en)) + item = QtWidgets.QTableWidgetItem(' / '.join(type_en)) item.setToolTip('\n'.join(type_en)) self.tableWidget_2.setItem(row, 2, item) @@ -215,11 +222,20 @@ class QPoke(QtWidgets.QDialog, Ui_Dialog): self.tableWidget_2.setItem(row, 12, item) self.tableWidget_2.resizeColumnToContents(1) + self.tableWidget_2.resizeColumnToContents(2) + self.tableWidget_2.setSortingEnabled(True) - def show_pokemon(self): - table = self.sender() - row = table.currentRow() - poke_id = table.item(row, 0).data(QtCore.Qt.ItemDataRole.UserRole) + def randomize(self): + select = randint(0, self.tableWidget_2.rowCount()) + self.show_pokemon(select) + + def show_pokemon(self, row: int = None): + table = self.tableWidget_2 + if row is None: + row = table.currentRow() + + species_id = table.item(row, 0).data(QtCore.Qt.ItemDataRole.UserRole) + poke_id = table.item(row, 0).data(QtCore.Qt.ItemDataRole.UserRole+1) pokemon_name = table.item(row, 1).text() connection = get_connection(self._db) @@ -227,7 +243,7 @@ class QPoke(QtWidgets.QDialog, Ui_Dialog): cursor.execute( 'SELECT p.id FROM pokemon p WHERE p.species_id = ?', - (poke_id,) + (species_id,) ) pokemon = cursor.fetchall() @@ -237,9 +253,14 @@ class QPoke(QtWidgets.QDialog, Ui_Dialog): for i in range(1, self.tabWidget.count()): self.tabWidget.setTabVisible(i, False) + widget_idx = 0 + for i, p in enumerate(pokemon): entry_widget = self.tabWidget.widget(i) + if poke_id == p[0]: + widget_idx = i + if entry_widget is None: self.tabWidget.addTab(PokemonEntry(p[0]), '') @@ -247,12 +268,13 @@ class QPoke(QtWidgets.QDialog, Ui_Dialog): self.tabWidget.setTabVisible(i, True) name = self.tabWidget.widget(i).create_pokemon(p[0]) self.tabWidget.setTabText(i, name) + self.tabWidget.setCurrentIndex(widget_idx) class PokemonEntry(QtWidgets.QWidget, Ui_Form): _db = '' - def __init__(self, pokemon_id, parent=None): + def __init__(self, pokemon_id: int, parent=None): super().__init__(parent=parent) self.setupUi(self) @@ -275,7 +297,7 @@ class PokemonEntry(QtWidgets.QWidget, Ui_Form): self.species_label.setToolTip(species['genus_de']) self.height_label.setText(f"{pokemon['height'] / 10} m") - self.weight_label.setText(f"{pokemon['weight']} kg") + self.weight_label.setText(f"{pokemon['weight'] / 10} kg") if species['gender_ratio'] == -1: gender = "Gender unknown" @@ -326,10 +348,23 @@ class PokemonEntry(QtWidgets.QWidget, Ui_Form): self.type_labels[slot].setToolTip(QPoke.types[type_id][0]) evolutions = self.make_evolution(pokemon['evolution_id']) - evo_text = [] - for e in evolutions: - evo_text.append(f'{e[0]} (#{e[1]:04d}) to {e[2]} (#{e[3]:04d}) \t\t ({e[4]})') - self.evolution_bar.setText('
'.join(evo_text)) + + self.tableWidget.clear() + self.tableWidget.setColumnCount(4) + self.tableWidget.setRowCount(len(evolutions)) + + for i, e in enumerate(evolutions): + item = QtWidgets.QTableWidgetItem(f'{e[0]} (#{e[1]:04d})') + self.tableWidget.setItem(i, 0, item) + item = QtWidgets.QTableWidgetItem('to') + self.tableWidget.setItem(i, 1, item) + item = QtWidgets.QTableWidgetItem(f'{e[2]} (#{e[3]:04d})') + self.tableWidget.setItem(i, 2, item) + item = QtWidgets.QTableWidgetItem(f'{e[4]}') + self.tableWidget.setItem(i, 3, item) + + self.tableWidget.resizeColumnsToContents() + self.tableWidget.resizeRowsToContents() if form['full_name_en'] is not None: return form['full_name_en'] @@ -438,7 +473,6 @@ class PokemonEntry(QtWidgets.QWidget, Ui_Form): return form, types - @cache def make_evolution(self, poke_id: int): steps = [] @@ -448,6 +482,7 @@ class PokemonEntry(QtWidgets.QWidget, Ui_Form): cursor.execute('SELECT * FROM evolution_names WHERE id = ?', (poke_id,)) chain = cursor.fetchall() + conn.close() trigger_texts = [ None, @@ -497,7 +532,6 @@ class PokemonEntry(QtWidgets.QWidget, Ui_Form): } for c in chain: - lvl0 = c["name_en"] if c['gender'] == 1: lvl0 += ' (female)' @@ -519,17 +553,4 @@ class PokemonEntry(QtWidgets.QWidget, Ui_Form): (lvl0, c['evolves_from'], c['evolve_en'], c['species_id'], ', '.join(filter(lambda x: x, level_text))) ) - conn.close() - return steps - - -if __name__ == '__main__': - app = QtWidgets.QApplication([]) - - sourcedb = 'pokemon.sqlite' - - w = QPoke(sourcedb) - w.show() - - app.exec() diff --git a/src/gui_qt/main/mainwindow.py b/src/gui_qt/main/mainwindow.py index 713eb75..d4c28eb 100644 --- a/src/gui_qt/main/mainwindow.py +++ b/src/gui_qt/main/mainwindow.py @@ -677,9 +677,10 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow): from ..math.skipping import QSkipDialog dial = QSkipDialog(self) - dial.exec() + res = dial.exec() - self.management.skip_points(**dial.get_arguments()) + if res: + self.management.skip_points(**dial.get_arguments()) @QtCore.pyqtSlot(name='on_action_coup_calc_triggered') def coupling_dialog(self): @@ -984,13 +985,21 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow): @QtCore.pyqtSlot(name='on_actionFunction_editor_triggered') def edit_models(self): if self.editor is None: - from ..lib.usermodeleditor import QUsermodelEditor + from ..editors.usermodeleditor import QUsermodelEditor self.editor = QUsermodelEditor(config_paths() / 'usermodels.py', parent=self) self.editor.modelsChanged.connect(lambda: self.fit_dialog.read_and_load_functions()) self.editor.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) self.editor.show() + @QtCore.pyqtSlot(name='on_actionUse_script_triggered') + def open_editor(self): + from ..editors.script_editor import QEditor + + editor = QEditor(self.path, parent=self) + editor.runSignal.connect(self.management.run_script) + editor.show() + @QtCore.pyqtSlot(list, bool) def extend_fit(self, sets: list, only_subplots: bool): if only_subplots: diff --git a/src/gui_qt/main/management.py b/src/gui_qt/main/management.py index 21715fa..31553e3 100644 --- a/src/gui_qt/main/management.py +++ b/src/gui_qt/main/management.py @@ -1033,7 +1033,7 @@ class UpperManagement(QtCore.QObject): else: data = self.data[sets[0]] if isinstance(data.data, new_type): - error_list.append(f'{data.name} is alreade of type {new_type.__name__}') + error_list.append(f'{data.name} is already of type {new_type.__name__}') continue new_data = new_type(data.x, np.zeros(data.x.size)) @@ -1067,6 +1067,8 @@ class UpperManagement(QtCore.QObject): @QtCore.pyqtSlot(list, list, bool) def eval_expression(self, cmds: list, set_ids: list, overwrite: bool): + if self.namespace is None: + self.namespace = self.get_namespace() ns = self.namespace.flatten() if overwrite: @@ -1099,13 +1101,28 @@ class UpperManagement(QtCore.QObject): if failures: err_msg = QtWidgets.QMessageBox(parent=self.sender()) - err_msg.setText('One or more errors occured during evaluation.') + err_msg.setText('One or more errors occurred during evaluation.') err_msg.setDetailedText('\n'.join(f'{d.name} failed with error: {err.args}' for d, err in failures)) err_msg.exec() self.sender().success = not failures self.sender().add_data(self.active_sets) + @QtCore.pyqtSlot(str) + def run_script(self, text): + self.namespace = self.get_namespace() + ns = self.namespace.flatten() + ns['return_list'] = [] + + # custom namespace must be available in global namespace of exec, otherwise imports do not work in functions + exec(text, ns, ns) + + new_sets = [] + for new_data in ns['return_list']: + new_sets.append(self.add(new_data)) + + self.newData.emit(new_sets, '') + @QtCore.pyqtSlot(list, dict) def create_from_function(self, cmds: list, opts: dict): ns = dict(self.namespace.flatten()) diff --git a/src/nmreval/distributions/energy.py b/src/nmreval/distributions/energy.py index 059b2a5..31331ed 100644 --- a/src/nmreval/distributions/energy.py +++ b/src/nmreval/distributions/energy.py @@ -95,7 +95,7 @@ def _integrate_c(func, omega: np.ndarray, temperature: np.ndarray, tau0: float, for o, t in product(omega, temperature): c = (c_double * 5)(o, tau0, e_m, e_b, t) user_data = cast(pointer(c), c_void_p) - area = quad(LowLevelCallable(func, user_data), 0, np.infty, epsabs=1e-13)[0] + area = quad(LowLevelCallable(func, user_data), 0, np.inf, epsabs=1e-13)[0] res.append(area) @@ -111,7 +111,7 @@ def _integrate_py(func, axis, temp, tau0, e_m, e_b): e_axis = np.linspace(max(0., e_m - 50*e_b), e_m + 50*e_b, num=5001) ret_val = [] for o, tt in product(x, temperature): - ret_val.append(simpson(func(e_axis, o, tau0, e_m, e_b, tt), e_axis)) + ret_val.append(simpson(y=func(e_axis, o, tau0, e_m, e_b, tt), x=e_axis)) ret_val = np.array(ret_val).reshape(x.shape[0], temperature.shape[0]) diff --git a/src/resources/_ui/basewindow.ui b/src/resources/_ui/basewindow.ui index 85c1f68..e2c4cab 100644 --- a/src/resources/_ui/basewindow.ui +++ b/src/resources/_ui/basewindow.ui @@ -192,6 +192,7 @@ + @@ -1049,6 +1050,11 @@ Remove data points outside visible y range. Uses real part of points. + + + Use script... + + diff --git a/src/resources/_ui/pokeentry.ui b/src/resources/_ui/pokeentry.ui index e320619..c8d6fe1 100644 --- a/src/resources/_ui/pokeentry.ui +++ b/src/resources/_ui/pokeentry.ui @@ -25,10 +25,50 @@ - + 12 + + 3 + + + 3 + + + 3 + + + 3 + + + + + National No. + + + + + + + TextLabel + + + + + + + Species + + + + + + + TextLabel + + + @@ -57,51 +97,13 @@ - - + + - Weight + Abilities - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Height - - - - - - - 0.0 m - - - - - - - 0.0 kg - - - - - - - Species + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop @@ -130,44 +132,41 @@ - - + + - TextLabel + Height - - + + - Abilities - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + 0.0 m - + + + + Weight + + + + + + + 0.0 kg + + + + TextLabel - - - - National No. - - - - - - - TextLabel - - - @@ -414,24 +413,46 @@ QProgressBar::chunk { 3 - - - QFrame::NoFrame + + + background-color: transparent; - - QFrame::Raised + + QAbstractItemView::NoEditTriggers - - 0 + + false - - TextLabel + + Qt::NoPen + + false + + + false + + + false + + + + + Qt::Vertical + + + + 20 + 40 + + + + diff --git a/src/resources/_ui/pokewindow.ui b/src/resources/_ui/pokewindow.ui index a3dcc00..c45fd56 100644 --- a/src/resources/_ui/pokewindow.ui +++ b/src/resources/_ui/pokewindow.ui @@ -6,7 +6,7 @@ 0 0 - 1526 + 1687 991 @@ -14,13 +14,46 @@ Gotta catch 'em all! - - + + + + Random + + - + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + QDialogButtonBox::Close + + + + Qt::Horizontal @@ -150,19 +183,18 @@ + + + 418 + 0 + + -1 - - - - QDialogButtonBox::Close - - -