dev #295
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										0
									
								
								src/gui_qt/editors/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/gui_qt/editors/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -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)
 | 
			
		||||
							
								
								
									
										137
									
								
								src/gui_qt/editors/script_editor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								src/gui_qt/editors/script_editor.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,137 @@
 | 
			
		||||
from __future__ import annotations
 | 
			
		||||
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
 | 
			
		||||
from ..Qt import QtWidgets, QtCore, QtGui
 | 
			
		||||
from .codeeditor import EditorWidget
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QEditor(QtWidgets.QMainWindow):
 | 
			
		||||
    runSignal = QtCore.pyqtSignal(str)
 | 
			
		||||
 | 
			
		||||
    def __init__(self, path: str | Path = None, parent=None):
 | 
			
		||||
        super().__init__(parent=parent)
 | 
			
		||||
 | 
			
		||||
        self._init_gui()
 | 
			
		||||
 | 
			
		||||
        self.fname = None
 | 
			
		||||
        self._dir = None
 | 
			
		||||
        if path is not None:
 | 
			
		||||
            self.read_file(path)
 | 
			
		||||
 | 
			
		||||
    def _init_gui(self):
 | 
			
		||||
        self.centralwidget = QtWidgets.QWidget(self)
 | 
			
		||||
 | 
			
		||||
        layout = QtWidgets.QVBoxLayout(self.centralwidget)
 | 
			
		||||
        layout.setContentsMargins(3, 3, 3, 3)
 | 
			
		||||
        layout.setSpacing(3)
 | 
			
		||||
 | 
			
		||||
        self.edit_field = EditorWidget(self.centralwidget)
 | 
			
		||||
        font = QtGui.QFont('default')
 | 
			
		||||
        font.setStyleHint(font.Monospace)
 | 
			
		||||
        font.setPointSize(10)
 | 
			
		||||
        self.edit_field.setFont(font)
 | 
			
		||||
 | 
			
		||||
        layout.addWidget(self.edit_field)
 | 
			
		||||
        self.setCentralWidget(self.centralwidget)
 | 
			
		||||
 | 
			
		||||
        self.statusbar = QtWidgets.QStatusBar(self)
 | 
			
		||||
        self.setStatusBar(self.statusbar)
 | 
			
		||||
 | 
			
		||||
        self.menubar = self.menuBar()
 | 
			
		||||
 | 
			
		||||
        self.menuFile = QtWidgets.QMenu('File', self.menubar)
 | 
			
		||||
        self.menubar.addMenu(self.menuFile)
 | 
			
		||||
 | 
			
		||||
        self.menuFile.addAction('Open...', self.open_file, QtGui.QKeySequence.Open)
 | 
			
		||||
        self.menuFile.addAction('Save', self.overwrite_file, QtGui.QKeySequence.Save)
 | 
			
		||||
        self.menuFile.addAction('Save as...', self.save_file, QtGui.QKeySequence('Ctrl+Shift+S'))
 | 
			
		||||
        self.menuFile.addSeparator()
 | 
			
		||||
        self.menuFile.addAction('Close', self.close, QtGui.QKeySequence.Quit)
 | 
			
		||||
 | 
			
		||||
        self.resize(800, 600)
 | 
			
		||||
        self.setGeometry(
 | 
			
		||||
            QtWidgets.QStyle.alignedRect(
 | 
			
		||||
                QtCore.Qt.LayoutDirection.LeftToRight,
 | 
			
		||||
                QtCore.Qt.AlignmentFlag.AlignCenter,
 | 
			
		||||
                self.size(),
 | 
			
		||||
                QtWidgets.qApp.desktop().availableGeometry()
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def is_modified(self):
 | 
			
		||||
        return self.edit_field.editor.document().isModified()
 | 
			
		||||
 | 
			
		||||
    def set_modified(self, val: bool):
 | 
			
		||||
        self.edit_field.editor.document().setModified(val)
 | 
			
		||||
 | 
			
		||||
    @QtCore.pyqtSlot()
 | 
			
		||||
    def open_file(self):
 | 
			
		||||
        overwrite = self.changes_saved
 | 
			
		||||
 | 
			
		||||
        if overwrite:
 | 
			
		||||
            fname, _ = QtWidgets.QFileDialog.getOpenFileName(directory=str(self._dir))
 | 
			
		||||
            if fname:
 | 
			
		||||
                self.read_file(fname)
 | 
			
		||||
 | 
			
		||||
    def read_file(self, fname: str | Path):
 | 
			
		||||
        self.set_fname_opts(fname)
 | 
			
		||||
 | 
			
		||||
        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):
 | 
			
		||||
        fname = Path(fname)
 | 
			
		||||
        if fname.is_file():
 | 
			
		||||
            self.fname = Path(fname)
 | 
			
		||||
            self._dir = self.fname.parent
 | 
			
		||||
        elif fname.is_dir():
 | 
			
		||||
            self._dir = fname
 | 
			
		||||
        self.setWindowTitle('Edit ' + str(fname))
 | 
			
		||||
 | 
			
		||||
    def changes_saved(self) -> bool:
 | 
			
		||||
        if not self.is_modified():
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
        ret = QtWidgets.QMessageBox.question(self, 'Time to think',
 | 
			
		||||
                                             '<h4><p>The document was modified.</p>\n'
 | 
			
		||||
                                             '<p>Do you want to save changes?</p></h4>',
 | 
			
		||||
                                             QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No |
 | 
			
		||||
                                             QtWidgets.QMessageBox.Cancel)
 | 
			
		||||
        if ret == QtWidgets.QMessageBox.Yes:
 | 
			
		||||
            self.save_file()
 | 
			
		||||
 | 
			
		||||
        if ret == QtWidgets.QMessageBox.No:
 | 
			
		||||
            self.set_modified(False)
 | 
			
		||||
 | 
			
		||||
        return not self.is_modified()
 | 
			
		||||
 | 
			
		||||
    @QtCore.pyqtSlot()
 | 
			
		||||
    def save_file(self):
 | 
			
		||||
        outfile, _ = QtWidgets.QFileDialog().getSaveFileName(parent=self, caption='Save file', directory=str(self._dir))
 | 
			
		||||
 | 
			
		||||
        if outfile:
 | 
			
		||||
            with open(outfile, 'w') as f:
 | 
			
		||||
                f.write(self.edit_field.toPlainText())
 | 
			
		||||
 | 
			
		||||
            self.set_fname_opts(outfile)
 | 
			
		||||
 | 
			
		||||
            self.set_modified(False)
 | 
			
		||||
 | 
			
		||||
        return self.is_modified()
 | 
			
		||||
 | 
			
		||||
    @QtCore.pyqtSlot()
 | 
			
		||||
    def overwrite_file(self):
 | 
			
		||||
        if self.fname is not None:
 | 
			
		||||
            with self.fname.open('w') as f:
 | 
			
		||||
                f.write(self.edit_field.toPlainText())
 | 
			
		||||
 | 
			
		||||
        self.modelsChanged.emit()
 | 
			
		||||
 | 
			
		||||
        self.set_modified(False)
 | 
			
		||||
 | 
			
		||||
    def closeEvent(self, evt: QtGui.QCloseEvent):
 | 
			
		||||
        self.runSignal.emit(self.edit_field.toPlainText())
 | 
			
		||||
 | 
			
		||||
        super().closeEvent(evt)
 | 
			
		||||
@@ -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,10 +50,14 @@ 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()
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def is_modified(self):
 | 
			
		||||
        return self.edit_field.editor.document().isModified()
 | 
			
		||||
@@ -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']
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -985,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:
 | 
			
		||||
 
 | 
			
		||||
@@ -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,27 @@ 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'] = []
 | 
			
		||||
 | 
			
		||||
        exec(text, globals(), 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())
 | 
			
		||||
 
 | 
			
		||||
@@ -192,6 +192,7 @@
 | 
			
		||||
    <addaction name="menuCut_to_visible_range"/>
 | 
			
		||||
    <addaction name="separator"/>
 | 
			
		||||
    <addaction name="actionChange_datatypes"/>
 | 
			
		||||
    <addaction name="actionUse_script"/>
 | 
			
		||||
   </widget>
 | 
			
		||||
   <widget class="QMenu" name="menuHelp">
 | 
			
		||||
    <property name="title">
 | 
			
		||||
@@ -1049,6 +1050,11 @@
 | 
			
		||||
    <string>Remove data points outside visible y range. Uses real part of points.</string>
 | 
			
		||||
   </property>
 | 
			
		||||
  </action>
 | 
			
		||||
  <action name="actionUse_script">
 | 
			
		||||
   <property name="text">
 | 
			
		||||
    <string>Use script...</string>
 | 
			
		||||
   </property>
 | 
			
		||||
  </action>
 | 
			
		||||
 </widget>
 | 
			
		||||
 <customwidgets>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user