Просмотр исходного кода

- working on a proper GCode Editor

Marius Stanciu 5 лет назад
Родитель
Сommit
9e8ab610b4
7 измененных файлов с 245 добавлено и 21 удалено
  1. 4 0
      CHANGELOG.md
  2. 13 9
      appEditors/AppTextEditor.py
  3. 199 0
      appEditors/appGCodeEditor.py
  4. 7 2
      appGUI/GUIElements.py
  5. 1 1
      appGUI/ObjectUI.py
  6. 18 3
      appObjects/FlatCAMCNCJob.py
  7. 3 6
      app_Main.py

+ 4 - 0
CHANGELOG.md

@@ -7,6 +7,10 @@ CHANGELOG for FlatCAM beta
 
 =================================================
 
+22.07.2020
+
+- working on a proper GCode Editor
+
 21.07.2020
 
 - updated the FCRadio class with a method that allow disabling certain options

+ 13 - 9
appEditors/AppTextEditor.py

@@ -5,7 +5,7 @@
 # MIT Licence                                              #
 # ##########################################################
 
-from appGUI.GUIElements import FCFileSaveDialog, FCEntry, FCTextAreaExtended, FCTextAreaLineNumber
+from appGUI.GUIElements import FCFileSaveDialog, FCEntry, FCTextAreaExtended, FCTextAreaLineNumber, FCButton
 from PyQt5 import QtPrintSupport, QtWidgets, QtCore, QtGui
 
 from reportlab.platypus import SimpleDocTemplate, Paragraph
@@ -30,6 +30,7 @@ class AppTextEditor(QtWidgets.QWidget):
 
         self.app = app
         self.plain_text = plain_text
+        self.callback = lambda x: None
 
         self.setSizePolicy(
             QtWidgets.QSizePolicy.MinimumExpanding,
@@ -71,17 +72,17 @@ class AppTextEditor(QtWidgets.QWidget):
         if text:
             self.code_editor.setPlainText(text)
 
-        self.buttonPreview = QtWidgets.QPushButton(_('Print Preview'))
+        self.buttonPreview = FCButton(_('Print Preview'))
         self.buttonPreview.setIcon(QtGui.QIcon(self.app.resource_location + '/preview32.png'))
         self.buttonPreview.setToolTip(_("Open a OS standard Preview Print window."))
         self.buttonPreview.setMinimumWidth(100)
 
-        self.buttonPrint = QtWidgets.QPushButton(_('Print Code'))
+        self.buttonPrint = FCButton(_('Print Code'))
         self.buttonPrint.setIcon(QtGui.QIcon(self.app.resource_location + '/printer32.png'))
         self.buttonPrint.setToolTip(_("Open a OS standard Print window."))
         self.buttonPrint.setMinimumWidth(100)
 
-        self.buttonFind = QtWidgets.QPushButton(_('Find in Code'))
+        self.buttonFind = FCButton(_('Find in Code'))
         self.buttonFind.setIcon(QtGui.QIcon(self.app.resource_location + '/find32.png'))
         self.buttonFind.setToolTip(_("Will search and highlight in yellow the string in the Find box."))
         self.buttonFind.setMinimumWidth(100)
@@ -89,7 +90,7 @@ class AppTextEditor(QtWidgets.QWidget):
         self.entryFind = FCEntry()
         self.entryFind.setToolTip(_("Find box. Enter here the strings to be searched in the text."))
 
-        self.buttonReplace = QtWidgets.QPushButton(_('Replace With'))
+        self.buttonReplace = FCButton(_('Replace With'))
         self.buttonReplace.setIcon(QtGui.QIcon(self.app.resource_location + '/replace32.png'))
         self.buttonReplace.setToolTip(_("Will replace the string from the Find box with the one in the Replace box."))
         self.buttonReplace.setMinimumWidth(100)
@@ -101,22 +102,22 @@ class AppTextEditor(QtWidgets.QWidget):
         self.sel_all_cb.setToolTip(_("When checked it will replace all instances in the 'Find' box\n"
                                      "with the text in the 'Replace' box.."))
 
-        self.button_copy_all = QtWidgets.QPushButton(_('Copy All'))
+        self.button_copy_all = FCButton(_('Copy All'))
         self.button_copy_all.setIcon(QtGui.QIcon(self.app.resource_location + '/copy_file32.png'))
         self.button_copy_all.setToolTip(_("Will copy all the text in the Code Editor to the clipboard."))
         self.button_copy_all.setMinimumWidth(100)
 
-        self.buttonOpen = QtWidgets.QPushButton(_('Open Code'))
+        self.buttonOpen = FCButton(_('Open Code'))
         self.buttonOpen.setIcon(QtGui.QIcon(self.app.resource_location + '/folder32_bis.png'))
         self.buttonOpen.setToolTip(_("Will open a text file in the editor."))
         self.buttonOpen.setMinimumWidth(100)
 
-        self.buttonSave = QtWidgets.QPushButton(_('Save Code'))
+        self.buttonSave = FCButton(_('Save Code'))
         self.buttonSave.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png'))
         self.buttonSave.setToolTip(_("Will save the text in the editor into a file."))
         self.buttonSave.setMinimumWidth(100)
 
-        self.buttonRun = QtWidgets.QPushButton(_('Run Code'))
+        self.buttonRun = FCButton(_('Run Code'))
         self.buttonRun.setToolTip(_("Will run the TCL commands found in the text file, one by one."))
         self.buttonRun.setMinimumWidth(100)
 
@@ -162,6 +163,9 @@ class AppTextEditor(QtWidgets.QWidget):
 
         self.code_edited = ''
 
+    def set_callback(self, callback):
+        self.callback = callback
+
     def handlePrint(self):
         self.app.defaults.report_usage("handlePrint()")
 

+ 199 - 0
appEditors/appGCodeEditor.py

@@ -0,0 +1,199 @@
+# ##########################################################
+# FlatCAM: 2D Post-processing for Manufacturing            #
+# File Author: Marius Adrian Stanciu (c)                   #
+# Date: 07/22/2020                                         #
+# MIT Licence                                              #
+# ##########################################################
+
+from appEditors.AppTextEditor import AppTextEditor
+from appObjects import FlatCAMCNCJob
+from appGUI.GUIElements import FCFileSaveDialog, FCEntry, FCTextAreaExtended, FCTextAreaLineNumber, FCButton
+from PyQt5 import QtWidgets, QtCore, QtGui
+
+# from io import StringIO
+
+import logging
+
+import gettext
+import appTranslation as fcTranslate
+import builtins
+
+fcTranslate.apply_language('strings')
+if '_' not in builtins.__dict__:
+    _ = gettext.gettext
+
+log = logging.getLogger('base')
+
+
+class appGCodeEditor(QtCore.QObject):
+
+    def __init__(self, app, parent=None):
+        super().__init__(parent=parent)
+
+        self.app = app
+        self.plain_text = ''
+        self.callback = lambda x: None
+
+        self.ui = appGCodeEditorUI(app=self.app)
+
+        # #################################################################################
+        # ################### SIGNALS #####################################################
+        # #################################################################################
+
+        self.gcode_obj = None
+        self.code_edited = ''
+
+    def set_ui(self):
+        pass
+
+    def build_ui(self):
+        pass
+
+    def ui_connect(self):
+        pass
+
+    def ui_disconnect(self):
+        pass
+
+    def handleTextChanged(self):
+        # enable = not self.ui.code_editor.document().isEmpty()
+        # self.ui.buttonPrint.setEnabled(enable)
+        # self.ui.buttonPreview.setEnabled(enable)
+
+        self.buttonSave.setStyleSheet("QPushButton {color: red;}")
+        self.buttonSave.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as_red.png'))
+
+    def edit_fcgcode(self, cnc_obj):
+        assert isinstance(cnc_obj, FlatCAMCNCJob)
+        self.gcode_obj = cnc_obj
+
+        preamble = str(self.ui.prepend_text.get_value())
+        postamble = str(self.ui.append_text.get_value())
+
+        gcode_text = self.gcode_obj.source_file
+
+        self.gcode_editor_tab.buttonSave.clicked.connect(self.on_update_source_file)
+
+        self.app.inform.emit('[success] %s...' % _('Loaded Machine Code into Code Editor'))
+
+        self.ui.gcode_editor_tab.load_text(self, gcode_text, move_to_start=True, clear_text=True)
+
+    def update_gcode(self):
+        my_gcode = self.ui.gcode_editor_tab.code_editor.toPlainText()
+        self.gcode_obj.source_file = my_gcode
+
+        self.ui.gcode_editor_tab.buttonSave.setStyleSheet("")
+        self.ui.gcode_editor_tab.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png'))
+
+    def handleOpen(self, filt=None):
+        self.app.defaults.report_usage("handleOpen()")
+
+        if filt:
+            _filter_ = filt
+        else:
+            _filter_ = "G-Code Files (*.nc);; G-Code Files (*.txt);; G-Code Files (*.tap);; G-Code Files (*.cnc);; " \
+                       "All Files (*.*)"
+
+        path, _f = QtWidgets.QFileDialog.getOpenFileName(
+            caption=_('Open file'), directory=self.app.get_last_folder(), filter=_filter_)
+
+        if path:
+            file = QtCore.QFile(path)
+            if file.open(QtCore.QIODevice.ReadOnly):
+                stream = QtCore.QTextStream(file)
+                self.code_edited = stream.readAll()
+                self.ui.gcode_editor_tab.load_text(self, self.code_edited, move_to_start=True, clear_text=True)
+                file.close()
+
+
+class appGCodeEditorUI:
+    def __init__(self, app):
+        self.app = app
+
+        # Number of decimals used by tools in this class
+        self.decimals = self.app.decimals
+
+        # ## Current application units in Upper Case
+        self.units = self.app.defaults['units'].upper()
+
+        # self.setSizePolicy(
+        #     QtWidgets.QSizePolicy.MinimumExpanding,
+        #     QtWidgets.QSizePolicy.MinimumExpanding
+        # )
+
+        self.layout = QtWidgets.QVBoxLayout()
+        self.layout.setContentsMargins(0, 0, 0, 0)
+
+        self.editor_frame = QtWidgets.QFrame()
+        self.editor_frame.setContentsMargins(0, 0, 0, 0)
+        self.layout.addWidget(self.editor_frame)
+
+        self.editor_layout = QtWidgets.QGridLayout(self.editor_frame)
+        self.editor_layout.setContentsMargins(2, 2, 2, 2)
+        self.editor_frame.setLayout(self.editor_layout)
+
+        # #############################################################################################################
+        # ############# ADD a new TAB in the PLot Tab Area
+        # #############################################################################################################
+        self.gcode_editor_tab = AppTextEditor(app=self.app, plain_text=True)
+
+        # add the tab if it was closed
+        self.app.ui.plot_tab_area.addTab(self.gcode_editor_tab, '%s' % _("Code Editor"))
+        self.gcode_editor_tab.setObjectName('code_editor_tab')
+
+        # delete the absolute and relative position and messages in the infobar
+        self.app.ui.position_label.setText("")
+        self.app.ui.rel_position_label.setText("")
+
+        self.gcode_editor_tab.code_editor.completer_enable = False
+        self.gcode_editor_tab.buttonRun.hide()
+
+        # Switch plot_area to CNCJob tab
+        self.app.ui.plot_tab_area.setCurrentWidget(self.gcode_editor_tab)
+
+        self.gcode_editor_tab.t_frame.hide()
+        # then append the text from GCode to the text editor
+        try:
+            self.gcode_editor_tab.load_text(self.app.gcode_edited.getvalue(), move_to_start=True, clear_text=True)
+        except Exception as e:
+            log.debug('FlatCAMCNNJob.on_edit_code_click() -->%s' % str(e))
+            self.app.inform.emit('[ERROR] %s %s' % ('FlatCAMCNNJob.on_edit_code_click() -->', str(e)))
+            return
+
+        self.gcode_editor_tab.t_frame.show()
+        self.app.proc_container.view.set_idle()
+
+        self.layout.addStretch()
+
+        # Editor
+        self.exit_editor_button = QtWidgets.QPushButton(_('Exit Editor'))
+        self.exit_editor_button.setIcon(QtGui.QIcon(self.app.resource_location + '/power16.png'))
+        self.exit_editor_button.setToolTip(
+            _("Exit from Editor.")
+        )
+        self.exit_editor_button.setStyleSheet("""
+                                          QPushButton
+                                          {
+                                              font-weight: bold;
+                                          }
+                                          """)
+        self.layout.addWidget(self.exit_editor_button)
+        # ############################ FINSIHED GUI ###################################
+        # #############################################################################
+
+    def confirmation_message(self, accepted, minval, maxval):
+        if accepted is False:
+            self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' % (_("Edited value is out of range"),
+                                                                                  self.decimals,
+                                                                                  minval,
+                                                                                  self.decimals,
+                                                                                  maxval), False)
+        else:
+            self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
+
+    def confirmation_message_int(self, accepted, minval, maxval):
+        if accepted is False:
+            self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%d, %d]' %
+                                            (_("Edited value is out of range"), minval, maxval), False)
+        else:
+            self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)

+ 7 - 2
appGUI/GUIElements.py

@@ -1557,8 +1557,13 @@ class FCInputDialog(QtWidgets.QInputDialog):
 
 
 class FCButton(QtWidgets.QPushButton):
-    def __init__(self, parent=None):
-        super(FCButton, self).__init__(parent)
+    def __init__(self, text=None, checkable=None, click_callback=None, parent=None):
+        super(FCButton, self).__init__(text, parent)
+        if not checkable is None:
+            self.setCheckable(checkable)
+
+        if not click_callback is None:
+            self.clicked.connect(click_callback)
 
     def get_value(self):
         return self.isChecked()

+ 1 - 1
appGUI/ObjectUI.py

@@ -1870,7 +1870,7 @@ class CNCObjectUI(ObjectUI):
         self.custom_box.addWidget(self.updateplot_button)
 
         # Editor
-        self.editor_button = QtWidgets.QPushButton(_('GCode Editor'))
+        self.editor_button = FCButton(_('GCode Editor'))
         self.editor_button.setIcon(QtGui.QIcon(self.app.resource_location + '/edit_file32.png'))
 
         self.editor_button.setToolTip(

+ 18 - 3
appObjects/FlatCAMCNCJob.py

@@ -149,6 +149,7 @@ class CNCJobObject(FlatCAMObj, CNCjob):
 
         self.gcode_editor_tab = None
 
+        self.source_file = ''
         self.units_found = self.app.defaults['units']
 
     def build_ui(self):
@@ -538,10 +539,14 @@ class CNCJobObject(FlatCAMObj, CNCjob):
         self.ui.name_entry.set_value(new_name)
         self.on_name_activate(silent=True)
 
-        preamble = str(self.ui.prepend_text.get_value())
-        postamble = str(self.ui.append_text.get_value())
+        try:
+            preamble = str(self.ui.prepend_text.get_value())
+            postamble = str(self.ui.append_text.get_value())
+            gc = self.export_gcode(filename, preamble=preamble, postamble=postamble)
+        except Exception as err:
+            log.debug("CNCJobObject.export_gcode_handler() --> %s" % str(err))
+            gc = self.export_gcode(filename)
 
-        gc = self.export_gcode(filename, preamble=preamble, postamble=postamble)
         if gc == 'fail':
             return
 
@@ -597,8 +602,13 @@ class CNCJobObject(FlatCAMObj, CNCjob):
         self.gcode_editor_tab.t_frame.show()
         self.app.proc_container.view.set_idle()
 
+        self.gcode_editor_tab.buttonSave.clicked.connect(self.on_update_source_file)
+
         self.app.inform.emit('[success] %s...' % _('Loaded Machine Code into Code Editor'))
 
+    def on_update_source_file(self):
+        self.source_file = self.gcode_editor_tab.code_editor.toPlainText()
+
     def gcode_header(self, comment_start_symbol=None, comment_stop_symbol=None):
         """
         Will create a header to be added to all GCode files generated by FlatCAM
@@ -735,6 +745,11 @@ class CNCJobObject(FlatCAMObj, CNCjob):
 
         include_header = True
 
+        if preamble == '':
+            preamble = self.app.defaults["cncjob_prepend"]
+        if postamble == '':
+            preamble = self.app.defaults["cncjob_append"]
+
         try:
             if self.special_group:
                 self.app.inform.emit('[WARNING_NOTCL] %s %s %s.' %

+ 3 - 6
app_Main.py

@@ -7745,10 +7745,7 @@ class App(QtCore.QObject):
         # then append the text from GCode to the text editor
         if obj.kind == 'cncjob':
             try:
-                file = obj.export_gcode(
-                    preamble=self.defaults["cncjob_prepend"],
-                    postamble=self.defaults["cncjob_append"],
-                    to_file=True)
+                file = obj.export_gcode(to_file=True)
                 if file == 'fail':
                     return 'fail'
             except AttributeError:
@@ -8665,14 +8662,14 @@ class App(QtCore.QObject):
                 def job_thread_grb(app_obj):
                     ret = make_gerber()
                     if ret == 'fail':
-                        self.inform.emit('[ERROR_NOTCL] %s' % _('Could not export Gerber file.'))
+                        self.inform.emit('[ERROR_NOTCL] %s' % _('Could not export file.'))
                         return
 
                 self.worker_task.emit({'fcn': job_thread_grb, 'params': [self]})
         else:
             gret = make_gerber()
             if gret == 'fail':
-                self.inform.emit('[ERROR_NOTCL] %s' % _('Could not export Gerber file.'))
+                self.inform.emit('[ERROR_NOTCL] %s' % _('Could not export file.'))
                 return 'fail'
             if local_use is not None:
                 return gret