- working on a proper GCode Editor

This commit is contained in:
Marius Stanciu 2020-07-22 15:49:52 +03:00
parent 65d4f70b21
commit 9e8ab610b4
7 changed files with 245 additions and 21 deletions

View File

@ -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

View File

@ -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()")

View File

@ -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)

View File

@ -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()

View File

@ -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(

View File

@ -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.' %

View File

@ -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