- wip in the GCode Editor

This commit is contained in:
Marius Stanciu 2020-07-22 17:08:40 +03:00
parent 9e8ab610b4
commit cf78211a6f
9 changed files with 174 additions and 74 deletions

View File

@ -10,6 +10,7 @@ CHANGELOG for FlatCAM beta
22.07.2020 22.07.2020
- working on a proper GCode Editor - working on a proper GCode Editor
- wip in the GCode Editor
21.07.2020 21.07.2020

View File

@ -2569,7 +2569,7 @@ class AppExcEditor(QtCore.QObject):
self.set_ui() self.set_ui()
# now that we hava data, create the appGUI interface and add it to the Tool Tab # now that we have data, create the appGUI interface and add it to the Tool Tab
self.build_ui(first_run=True) self.build_ui(first_run=True)
# we activate this after the initial build as we don't need to see the tool been populated # we activate this after the initial build as we don't need to see the tool been populated

View File

@ -6,8 +6,8 @@
# ########################################################## # ##########################################################
from appEditors.AppTextEditor import AppTextEditor from appEditors.AppTextEditor import AppTextEditor
from appObjects import FlatCAMCNCJob from appObjects.FlatCAMCNCJob import CNCJobObject
from appGUI.GUIElements import FCFileSaveDialog, FCEntry, FCTextAreaExtended, FCTextAreaLineNumber, FCButton from appGUI.GUIElements import FCTextArea, FCEntry, FCButton
from PyQt5 import QtWidgets, QtCore, QtGui from PyQt5 import QtWidgets, QtCore, QtGui
# from io import StringIO # from io import StringIO
@ -25,7 +25,7 @@ if '_' not in builtins.__dict__:
log = logging.getLogger('base') log = logging.getLogger('base')
class appGCodeEditor(QtCore.QObject): class AppGCodeEditor(QtCore.QObject):
def __init__(self, app, parent=None): def __init__(self, app, parent=None):
super().__init__(parent=parent) super().__init__(parent=parent)
@ -34,7 +34,7 @@ class appGCodeEditor(QtCore.QObject):
self.plain_text = '' self.plain_text = ''
self.callback = lambda x: None self.callback = lambda x: None
self.ui = appGCodeEditorUI(app=self.app) self.ui = AppGCodeEditorUI(app=self.app)
# ################################################################################# # #################################################################################
# ################### SIGNALS ##################################################### # ################### SIGNALS #####################################################
@ -44,10 +44,44 @@ class appGCodeEditor(QtCore.QObject):
self.code_edited = '' self.code_edited = ''
def set_ui(self): def set_ui(self):
pass # #############################################################################################################
# ############# ADD a new TAB in the PLot Tab Area
# #############################################################################################################
self.ui.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.ui.gcode_editor_tab, '%s' % _("Code Editor"))
self.ui.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.ui.gcode_editor_tab.code_editor.completer_enable = False
self.ui.gcode_editor_tab.buttonRun.hide()
# Switch plot_area to CNCJob tab
self.app.ui.plot_tab_area.setCurrentWidget(self.ui.gcode_editor_tab)
self.ui.gcode_editor_tab.t_frame.hide()
self.ui.gcode_editor_tab.t_frame.show()
self.app.proc_container.view.set_idle()
# #############################################################################################################
# #############################################################################################################
self.ui.append_text.set_value(self.app.defaults["cncjob_append"])
self.ui.prepend_text.set_value(self.app.defaults["cncjob_prepend"])
self.ui.exit_editor_button.buttonSave.clicked.connect(self.update_fcgcode)
def build_ui(self): def build_ui(self):
pass # Remove anything else in the GUI Selected Tab
self.app.ui.selected_scroll_area.takeWidget()
# Put ourselves in the GUI Selected Tab
self.app.ui.selected_scroll_area.setWidget(self.ui.edit_widget)
# Switch notebook to Selected page
self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
def ui_connect(self): def ui_connect(self):
pass pass
@ -64,35 +98,31 @@ class appGCodeEditor(QtCore.QObject):
self.buttonSave.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as_red.png')) self.buttonSave.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as_red.png'))
def edit_fcgcode(self, cnc_obj): def edit_fcgcode(self, cnc_obj):
assert isinstance(cnc_obj, FlatCAMCNCJob) assert isinstance(cnc_obj, CNCJobObject)
self.gcode_obj = cnc_obj 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 gcode_text = self.gcode_obj.source_file
self.gcode_editor_tab.buttonSave.clicked.connect(self.on_update_source_file) self.set_ui()
self.build_ui()
# then append the text from GCode to the text editor
self.ui.gcode_editor_tab.load_text(gcode_text, move_to_start=True, clear_text=True)
self.app.inform.emit('[success] %s...' % _('Loaded Machine Code into Code Editor')) 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_fcgcode(self):
preamble = str(self.ui.prepend_text.get_value())
def update_gcode(self): postamble = str(self.ui.append_text.get_value())
my_gcode = self.ui.gcode_editor_tab.code_editor.toPlainText() my_gcode = self.ui.gcode_editor_tab.code_editor.toPlainText()
self.gcode_obj.source_file = my_gcode self.gcode_obj.source_file = my_gcode
self.ui.gcode_editor_tab.buttonSave.setStyleSheet("") self.ui.gcode_editor_tab.buttonSave.setStyleSheet("")
self.ui.gcode_editor_tab.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png')) self.ui.gcode_editor_tab.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png'))
def handleOpen(self, filt=None): def on_open_gcode(self):
self.app.defaults.report_usage("handleOpen()")
if filt: _filter_ = "G-Code Files (*.nc);; G-Code Files (*.txt);; G-Code Files (*.tap);; G-Code Files (*.cnc);; " \
_filter_ = filt "All Files (*.*)"
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( path, _f = QtWidgets.QFileDialog.getOpenFileName(
caption=_('Open file'), directory=self.app.get_last_folder(), filter=_filter_) caption=_('Open file'), directory=self.app.get_last_folder(), filter=_filter_)
@ -102,11 +132,11 @@ class appGCodeEditor(QtCore.QObject):
if file.open(QtCore.QIODevice.ReadOnly): if file.open(QtCore.QIODevice.ReadOnly):
stream = QtCore.QTextStream(file) stream = QtCore.QTextStream(file)
self.code_edited = stream.readAll() self.code_edited = stream.readAll()
self.ui.gcode_editor_tab.load_text(self, self.code_edited, move_to_start=True, clear_text=True) self.ui.gcode_editor_tab.load_text(self.code_edited, move_to_start=True, clear_text=True)
file.close() file.close()
class appGCodeEditorUI: class AppGCodeEditorUI:
def __init__(self, app): def __init__(self, app):
self.app = app self.app = app
@ -121,52 +151,96 @@ class appGCodeEditorUI:
# QtWidgets.QSizePolicy.MinimumExpanding # QtWidgets.QSizePolicy.MinimumExpanding
# ) # )
self.layout = QtWidgets.QVBoxLayout() self.gcode_editor_tab = None
self.layout.setContentsMargins(0, 0, 0, 0)
self.editor_frame = QtWidgets.QFrame() self.edit_widget = QtWidgets.QWidget()
self.editor_frame.setContentsMargins(0, 0, 0, 0) # ## Box for custom widgets
self.layout.addWidget(self.editor_frame) # This gets populated in offspring implementations.
layout = QtWidgets.QVBoxLayout()
self.edit_widget.setLayout(layout)
self.editor_layout = QtWidgets.QGridLayout(self.editor_frame) # add a frame and inside add a vertical box layout. Inside this vbox layout I add all the Drills widgets
self.editor_layout.setContentsMargins(2, 2, 2, 2) # this way I can hide/show the frame
self.editor_frame.setLayout(self.editor_layout) self.edit_frame = QtWidgets.QFrame()
self.edit_frame.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.edit_frame)
self.edit_box = QtWidgets.QVBoxLayout()
self.edit_box.setContentsMargins(0, 0, 0, 0)
self.edit_frame.setLayout(self.edit_box)
# ############################################################################################################# # ## Page Title box (spacing between children)
# ############# ADD a new TAB in the PLot Tab Area self.title_box = QtWidgets.QHBoxLayout()
# ############################################################################################################# self.edit_box.addLayout(self.title_box)
self.gcode_editor_tab = AppTextEditor(app=self.app, plain_text=True)
# add the tab if it was closed # ## Page Title icon
self.app.ui.plot_tab_area.addTab(self.gcode_editor_tab, '%s' % _("Code Editor")) pixmap = QtGui.QPixmap(self.app.resource_location + '/flatcam_icon32.png')
self.gcode_editor_tab.setObjectName('code_editor_tab') self.icon = QtWidgets.QLabel()
self.icon.setPixmap(pixmap)
self.title_box.addWidget(self.icon, stretch=0)
# delete the absolute and relative position and messages in the infobar # ## Title label
self.app.ui.position_label.setText("") self.title_label = QtWidgets.QLabel("<font size=5><b>%s</b></font>" % _('GCode Editor'))
self.app.ui.rel_position_label.setText("") self.title_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
self.title_box.addWidget(self.title_label, stretch=1)
self.gcode_editor_tab.code_editor.completer_enable = False # ## Object name
self.gcode_editor_tab.buttonRun.hide() self.name_box = QtWidgets.QHBoxLayout()
self.edit_box.addLayout(self.name_box)
name_label = QtWidgets.QLabel(_("Name:"))
self.name_box.addWidget(name_label)
self.name_entry = FCEntry()
self.name_box.addWidget(self.name_entry)
# Switch plot_area to CNCJob tab # Prepend text to GCode
self.app.ui.plot_tab_area.setCurrentWidget(self.gcode_editor_tab) prependlabel = QtWidgets.QLabel('%s:' % _('Prepend to CNC Code'))
prependlabel.setToolTip(
_("Type here any G-Code commands you would\n"
"like to add at the beginning of the G-Code file.")
)
self.edit_box.addWidget(prependlabel)
self.gcode_editor_tab.t_frame.hide() self.prepend_text = FCTextArea()
# then append the text from GCode to the text editor self.prepend_text.setPlaceholderText(
try: _("Type here any G-Code commands you would\n"
self.gcode_editor_tab.load_text(self.app.gcode_edited.getvalue(), move_to_start=True, clear_text=True) "like to add at the beginning of the G-Code file.")
except Exception as e: )
log.debug('FlatCAMCNNJob.on_edit_code_click() -->%s' % str(e)) self.edit_box.addWidget(self.prepend_text)
self.app.inform.emit('[ERROR] %s %s' % ('FlatCAMCNNJob.on_edit_code_click() -->', str(e)))
return
self.gcode_editor_tab.t_frame.show() # Append text to GCode
self.app.proc_container.view.set_idle() appendlabel = QtWidgets.QLabel('%s:' % _('Append to CNC Code'))
appendlabel.setToolTip(
_("Type here any G-Code commands you would\n"
"like to append to the generated file.\n"
"I.e.: M2 (End of program)")
)
self.edit_box.addWidget(appendlabel)
self.layout.addStretch() self.append_text = FCTextArea()
self.append_text.setPlaceholderText(
_("Type here any G-Code commands you would\n"
"like to append to the generated file.\n"
"I.e.: M2 (End of program)")
)
self.edit_box.addWidget(self.append_text)
h_lay = QtWidgets.QHBoxLayout()
h_lay.setAlignment(QtCore.Qt.AlignVCenter)
self.edit_box.addLayout(h_lay)
# GO Button
self.update_gcode_button = FCButton(_('Update Code'))
# self.update_gcode_button.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png'))
self.update_gcode_button.setToolTip(
_("Update the Gcode in the Editor with the values\n"
"in the 'Prepend' and 'Append' text boxes.")
)
h_lay.addWidget(self.update_gcode_button)
layout.addStretch()
# Editor # Editor
self.exit_editor_button = QtWidgets.QPushButton(_('Exit Editor')) self.exit_editor_button = FCButton(_('Exit Editor'))
self.exit_editor_button.setIcon(QtGui.QIcon(self.app.resource_location + '/power16.png')) self.exit_editor_button.setIcon(QtGui.QIcon(self.app.resource_location + '/power16.png'))
self.exit_editor_button.setToolTip( self.exit_editor_button.setToolTip(
_("Exit from Editor.") _("Exit from Editor.")
@ -177,9 +251,9 @@ class appGCodeEditorUI:
font-weight: bold; font-weight: bold;
} }
""") """)
self.layout.addWidget(self.exit_editor_button) layout.addWidget(self.exit_editor_button)
# ############################ FINSIHED GUI ################################### # ############################ FINSIHED GUI ##################################################################
# ############################################################################# # #############################################################################################################
def confirmation_message(self, accepted, minval, maxval): def confirmation_message(self, accepted, minval, maxval):
if accepted is False: if accepted is False:

View File

@ -595,8 +595,7 @@ class CNCJobObject(FlatCAMObj, CNCjob):
try: try:
self.gcode_editor_tab.load_text(self.app.gcode_edited.getvalue(), move_to_start=True, clear_text=True) self.gcode_editor_tab.load_text(self.app.gcode_edited.getvalue(), move_to_start=True, clear_text=True)
except Exception as e: except Exception as e:
log.debug('FlatCAMCNNJob.on_edit_code_click() -->%s' % str(e)) log.debug('FlatCAMCNCJob.on_edit_code_click() -->%s' % str(e))
self.app.inform.emit('[ERROR] %s %s' % ('FlatCAMCNNJob.on_edit_code_click() -->', str(e)))
return return
self.gcode_editor_tab.t_frame.show() self.gcode_editor_tab.t_frame.show()

View File

@ -1881,6 +1881,7 @@ class GeometryObject(FlatCAMObj, Geometry):
job_obj.z_pdepth = float(self.app.defaults["geometry_z_pdepth"]) job_obj.z_pdepth = float(self.app.defaults["geometry_z_pdepth"])
job_obj.feedrate_probe = float(self.app.defaults["geometry_feedrate_probe"]) job_obj.feedrate_probe = float(self.app.defaults["geometry_feedrate_probe"])
total_gcode = ''
for tooluid_key in list(tools_dict.keys()): for tooluid_key in list(tools_dict.keys()):
tool_cnt += 1 tool_cnt += 1
@ -1970,6 +1971,8 @@ class GeometryObject(FlatCAMObj, Geometry):
else: else:
dia_cnc_dict['gcode'] = res dia_cnc_dict['gcode'] = res
total_gcode += res
# tell gcode_parse from which point to start drawing the lines depending on what kind of # tell gcode_parse from which point to start drawing the lines depending on what kind of
# object is the source of gcode # object is the source of gcode
job_obj.toolchange_xy_type = "geometry" job_obj.toolchange_xy_type = "geometry"
@ -1993,6 +1996,8 @@ class GeometryObject(FlatCAMObj, Geometry):
}) })
dia_cnc_dict.clear() dia_cnc_dict.clear()
job_obj.source_file = total_gcode
# Object initialization function for app.app_obj.new_object() # Object initialization function for app.app_obj.new_object()
# RUNNING ON SEPARATE THREAD! # RUNNING ON SEPARATE THREAD!
def job_init_multi_geometry(job_obj, app_obj): def job_init_multi_geometry(job_obj, app_obj):
@ -2031,6 +2036,7 @@ class GeometryObject(FlatCAMObj, Geometry):
self.app.inform.emit('[ERROR_NOTCL] %s...' % _('Cancelled. Empty file, it has no geometry')) self.app.inform.emit('[ERROR_NOTCL] %s...' % _('Cancelled. Empty file, it has no geometry'))
return 'fail' return 'fail'
total_gcode = ''
for tooluid_key in list(tools_dict.keys()): for tooluid_key in list(tools_dict.keys()):
tool_cnt += 1 tool_cnt += 1
dia_cnc_dict = deepcopy(tools_dict[tooluid_key]) dia_cnc_dict = deepcopy(tools_dict[tooluid_key])
@ -2123,6 +2129,7 @@ class GeometryObject(FlatCAMObj, Geometry):
return 'fail' return 'fail'
else: else:
dia_cnc_dict['gcode'] = res dia_cnc_dict['gcode'] = res
total_gcode += res
self.app.inform.emit('[success] %s' % _("G-Code parsing in progress...")) self.app.inform.emit('[success] %s' % _("G-Code parsing in progress..."))
dia_cnc_dict['gcode_parsed'] = job_obj.gcode_parse() dia_cnc_dict['gcode_parsed'] = job_obj.gcode_parse()
@ -2149,6 +2156,8 @@ class GeometryObject(FlatCAMObj, Geometry):
}) })
dia_cnc_dict.clear() dia_cnc_dict.clear()
job_obj.source_file = total_gcode
if use_thread: if use_thread:
# To be run in separate thread # To be run in separate thread
def job_thread(a_obj): def job_thread(a_obj):
@ -2288,17 +2297,18 @@ class GeometryObject(FlatCAMObj, Geometry):
# it seems that the tolerance needs to be a lot lower value than 0.01 and it was hardcoded initially # it seems that the tolerance needs to be a lot lower value than 0.01 and it was hardcoded initially
# to a value of 0.0005 which is 20 times less than 0.01 # to a value of 0.0005 which is 20 times less than 0.01
tol = float(self.app.defaults['global_tolerance']) / 20 tol = float(self.app.defaults['global_tolerance']) / 20
job_obj.generate_from_geometry_2( res = job_obj.generate_from_geometry_2(self, tooldia=tooldia, offset=offset, tolerance=tol,
self, tooldia=tooldia, offset=offset, tolerance=tol, z_cut=z_cut, z_move=z_move, feedrate=feedrate,
z_cut=z_cut, z_move=z_move, feedrate_z=feedrate_z, feedrate_rapid=feedrate_rapid,
feedrate=feedrate, feedrate_z=feedrate_z, feedrate_rapid=feedrate_rapid, spindlespeed=spindlespeed, dwell=dwell, dwelltime=dwelltime,
spindlespeed=spindlespeed, dwell=dwell, dwelltime=dwelltime, multidepth=multidepth, depthpercut=depthperpass,
multidepth=multidepth, depthpercut=depthperpass, toolchange=toolchange, toolchangez=toolchangez,
toolchange=toolchange, toolchangez=toolchangez, toolchangexy=toolchangexy, toolchangexy=toolchangexy,
extracut=extracut, extracut_length=extracut_length, startz=startz, endz=endz, endxy=endxy, extracut=extracut, extracut_length=extracut_length,
pp_geometry_name=ppname_g startz=startz, endz=endz, endxy=endxy,
pp_geometry_name=ppname_g
) )
job_obj.source_file = res
# tell gcode_parse from which point to start drawing the lines depending on what kind of object is the # tell gcode_parse from which point to start drawing the lines depending on what kind of object is the
# source of gcode # source of gcode
job_obj.toolchange_xy_type = "geometry" job_obj.toolchange_xy_type = "geometry"

View File

@ -1797,6 +1797,7 @@ class ToolDrilling(AppTool, Excellon):
self.total_gcode_parsed += tool_gcode_parsed self.total_gcode_parsed += tool_gcode_parsed
job_obj.gcode = self.total_gcode job_obj.gcode = self.total_gcode
job_obj.source_file = self.total_gcode
job_obj.gcode_parsed = self.total_gcode_parsed job_obj.gcode_parsed = self.total_gcode_parsed
if job_obj.gcode == 'fail': if job_obj.gcode == 'fail':
return 'fail' return 'fail'

View File

@ -913,6 +913,7 @@ class SolderPaste(AppTool):
job_obj.options['xmax'] = xmax job_obj.options['xmax'] = xmax
job_obj.options['ymax'] = ymax job_obj.options['ymax'] = ymax
total_gcode = ''
for tooluid_key, tooluid_value in obj.tools.items(): for tooluid_key, tooluid_value in obj.tools.items():
# find the tool_dia associated with the tooluid_key # find the tool_dia associated with the tooluid_key
tool_dia = tooluid_value['tooldia'] tool_dia = tooluid_value['tooldia']
@ -934,6 +935,7 @@ class SolderPaste(AppTool):
return 'fail' return 'fail'
else: else:
tool_cnc_dict['gcode'] = res tool_cnc_dict['gcode'] = res
total_gcode += res
# ## PARSE GCODE # ## # ## PARSE GCODE # ##
tool_cnc_dict['gcode_parsed'] = job_obj.gcode_parse() tool_cnc_dict['gcode_parsed'] = job_obj.gcode_parse()
@ -949,6 +951,8 @@ class SolderPaste(AppTool):
}) })
tool_cnc_dict.clear() tool_cnc_dict.clear()
job_obj.source_file = total_gcode
if use_thread: if use_thread:
# To be run in separate thread # To be run in separate thread
def job_thread(app_obj): def job_thread(app_obj):

View File

@ -83,6 +83,7 @@ from appEditors.AppGeoEditor import AppGeoEditor
from appEditors.AppExcEditor import AppExcEditor from appEditors.AppExcEditor import AppExcEditor
from appEditors.AppGerberEditor import AppGerberEditor from appEditors.AppGerberEditor import AppGerberEditor
from appEditors.AppTextEditor import AppTextEditor from appEditors.AppTextEditor import AppTextEditor
from appEditors.appGCodeEditor import AppGCodeEditor
from appParsers.ParseHPGL2 import HPGL2 from appParsers.ParseHPGL2 import HPGL2
# FlatCAM Workers # FlatCAM Workers
@ -1574,6 +1575,12 @@ class App(QtCore.QObject):
self.grb_editor = AppGerberEditor(self) self.grb_editor = AppGerberEditor(self)
except Exception as es: except Exception as es:
log.debug("app_Main.__init__() --> Gerber Editor Error: %s" % str(es)) log.debug("app_Main.__init__() --> Gerber Editor Error: %s" % str(es))
try:
self.gcode_editor = AppGCodeEditor(self)
except Exception as es:
log.debug("app_Main.__init__() --> GCode Editor Error: %s" % str(es))
self.log.debug("Finished adding FlatCAM Editor's.") self.log.debug("Finished adding FlatCAM Editor's.")
self.set_ui_title(name=_("New Project - Not saved")) self.set_ui_title(name=_("New Project - Not saved"))
@ -2226,7 +2233,10 @@ class App(QtCore.QObject):
if self.ui.splitter.sizes()[0] == 0: if self.ui.splitter.sizes()[0] == 0:
self.ui.splitter.setSizes([1, 1]) self.ui.splitter.setSizes([1, 1])
edited_object.on_edit_code_click() # set call source to the Editor we go into
self.call_source = 'gcode_editor'
self.gcode_editor.edit_fcgcode(edited_object)
return return
# make sure that we can't select another object while in Editor Mode: # make sure that we can't select another object while in Editor Mode:

View File

@ -332,6 +332,7 @@ class TclCommandDrillcncjob(TclCommandSignaled):
job_obj.excellon_optimization_type = opt_type job_obj.excellon_optimization_type = opt_type
ret_val = job_obj.generate_from_excellon_by_tool(obj, tools, use_ui=False) ret_val = job_obj.generate_from_excellon_by_tool(obj, tools, use_ui=False)
job_obj.source_file = ret_val
if ret_val == 'fail': if ret_val == 'fail':
return 'fail' return 'fail'