From 44411cdc826cce142a8670d7fb3af57768f657a7 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Sun, 2 Aug 2020 16:27:30 +0300 Subject: [PATCH] - GCode Editor - closing the Editor will close also the Code Editor Tab - cleanup of the CNCJob UI; added a checkbox to signal if any append/prepend gcode was set in Preferences (unchecking it will override and disable the usage of the append/prepend GCode) - the start Gcode is now stored in the CNCJob object attribute gc_start - GCode Editor - finished adding the ability to select a row in the Tools table and select the related GCode --- CHANGELOG.md | 7 + appEditors/AppTextEditor.py | 2 - appEditors/appGCodeEditor.py | 151 +++++++++++++++++---- appGUI/ObjectUI.py | 248 ++++++++++++++++++---------------- appObjects/FlatCAMCNCJob.py | 184 ++++++++++++++----------- appObjects/FlatCAMGeometry.py | 20 ++- appTools/ToolDrilling.py | 32 +++-- app_Main.py | 11 +- camlib.py | 14 +- 9 files changed, 411 insertions(+), 258 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9865803e..b5c5dea7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ CHANGELOG for FlatCAM beta ================================================= +2.08.2020 + +- GCode Editor - closing the Editor will close also the Code Editor Tab +- cleanup of the CNCJob UI; added a checkbox to signal if any append/prepend gcode was set in Preferences (unchecking it will override and disable the usage of the append/prepend GCode) +- the start Gcode is now stored in the CNCJob object attribute gc_start +- GCode Editor - finished adding the ability to select a row in the Tools table and select the related GCode + 1.08.2020 - Tools Database: added a Cutout Tool Parameters section diff --git a/appEditors/AppTextEditor.py b/appEditors/AppTextEditor.py index 4efe000d..52e7eb8a 100644 --- a/appEditors/AppTextEditor.py +++ b/appEditors/AppTextEditor.py @@ -323,7 +323,6 @@ class AppTextEditor(QtWidgets.QWidget): callback() def handleFindGCode(self): - self.app.defaults.report_usage("handleFindGCode()") flags = QtGui.QTextDocument.FindCaseSensitively text_to_be_found = self.entryFind.get_value() @@ -334,7 +333,6 @@ class AppTextEditor(QtWidgets.QWidget): r = self.code_editor.find(str(text_to_be_found), flags) def handleReplaceGCode(self): - self.app.defaults.report_usage("handleReplaceGCode()") old = self.entryFind.get_value() new = self.entryReplace.get_value() diff --git a/appEditors/appGCodeEditor.py b/appEditors/appGCodeEditor.py index 1028f28e..ffabe439 100644 --- a/appEditors/appGCodeEditor.py +++ b/appEditors/appGCodeEditor.py @@ -59,10 +59,11 @@ class AppGCodeEditor(QtCore.QObject): # ############# ADD a new TAB in the PLot Tab Area # ############################################################################################################# self.ui.gcode_editor_tab = AppTextEditor(app=self.app, plain_text=True) + self.edit_area = self.ui.gcode_editor_tab.code_editor # 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') + self.ui.gcode_editor_tab.setObjectName('gcode_editor_tab') # delete the absolute and relative position and messages in the infobar self.app.ui.position_label.setText("") @@ -128,11 +129,23 @@ class AppGCodeEditor(QtCore.QObject): tool_idx = 0 row_no = 0 - n = len(self.gcode_obj.cnc_tools) + 2 + n = len(self.gcode_obj.cnc_tools) + 3 self.ui.cnc_tools_table.setRowCount(n) + # add the All Gcode selection + allgcode_item = QtWidgets.QTableWidgetItem('%s' % _("All GCode")) + allgcode_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.cnc_tools_table.setItem(row_no, 1, allgcode_item) + row_no += 1 + + # add the Header Gcode selection + header_item = QtWidgets.QTableWidgetItem('%s' % _("Header GCode")) + header_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.cnc_tools_table.setItem(row_no, 1, header_item) + row_no += 1 + # add the Start Gcode selection - start_item = QtWidgets.QTableWidgetItem('%s' % _("Header GCode")) + start_item = QtWidgets.QTableWidgetItem('%s' % _("Start GCode")) start_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.ui.cnc_tools_table.setItem(row_no, 1, start_item) @@ -168,11 +181,6 @@ class AppGCodeEditor(QtCore.QObject): # ## REMEMBER: THIS COLUMN IS HIDDEN IN OBJECTUI.PY # ## self.ui.cnc_tools_table.setItem(row_no, 5, tool_uid_item) # Tool unique ID) - # add the All Gcode selection - end_item = QtWidgets.QTableWidgetItem('%s' % _("All GCode")) - end_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.ui.cnc_tools_table.setItem(row_no + 1, 1, end_item) - self.ui.cnc_tools_table.resizeColumnsToContents() self.ui.cnc_tools_table.resizeRowsToContents() @@ -213,11 +221,23 @@ class AppGCodeEditor(QtCore.QObject): tool_idx = 0 row_no = 0 - n = len(self.gcode_obj.exc_cnc_tools) + 2 + n = len(self.gcode_obj.exc_cnc_tools) + 3 self.ui.exc_cnc_tools_table.setRowCount(n) + # add the All Gcode selection + allgcode_item = QtWidgets.QTableWidgetItem('%s' % _("All GCode")) + allgcode_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.exc_cnc_tools_table.setItem(row_no, 1, allgcode_item) + row_no += 1 + + # add the Header Gcode selection + header_item = QtWidgets.QTableWidgetItem('%s' % _("Header GCode")) + header_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.exc_cnc_tools_table.setItem(row_no, 1, header_item) + row_no += 1 + # add the Start Gcode selection - start_item = QtWidgets.QTableWidgetItem('%s' % _("Header GCode")) + start_item = QtWidgets.QTableWidgetItem('%s' % _("Start GCode")) start_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.ui.exc_cnc_tools_table.setItem(row_no, 1, start_item) @@ -249,11 +269,6 @@ class AppGCodeEditor(QtCore.QObject): self.ui.exc_cnc_tools_table.setItem(row_no, 4, tool_uid_item) # Tool unique ID) self.ui.exc_cnc_tools_table.setItem(row_no, 5, cutz_item) - # add the All Gcode selection - end_item = QtWidgets.QTableWidgetItem('%s' % _("All GCode")) - end_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.ui.exc_cnc_tools_table.setItem(row_no + 1, 1, end_item) - self.ui.exc_cnc_tools_table.resizeColumnsToContents() self.ui.exc_cnc_tools_table.resizeRowsToContents() @@ -327,12 +342,17 @@ class AppGCodeEditor(QtCore.QObject): :return: :rtype: """ + flags = QtGui.QTextDocument.FindCaseSensitively + self.edit_area.moveCursor(QtGui.QTextCursor.Start) + if self.gcode_obj.cnc_tools: - sel_model = self.ui.cnc_tools_table.selectionModel() + t_table = self.ui.cnc_tools_table elif self.gcode_obj.exc_cnc_tools: - sel_model = self.ui.exc_cnc_tools_table.selectionModel() + t_table = self.ui.exc_cnc_tools_table else: return + + sel_model = t_table.selectionModel() sel_indexes = sel_model.selectedIndexes() # it will iterate over all indexes which means all items in all columns too but I'm interested only on rows @@ -340,6 +360,81 @@ class AppGCodeEditor(QtCore.QObject): for idx in sel_indexes: sel_rows.add(idx.row()) + if 0 in sel_rows: + self.edit_area.selectAll() + return + + if 1 in sel_rows: + text_to_be_found = self.gcode_obj.gc_header + text_list = [x for x in text_to_be_found.split("\n") if x != ''] + + self.edit_area.find(str(text_list[0]), flags) + my_text_cursor = self.edit_area.textCursor() + start_sel = my_text_cursor.selectionStart() + + end_sel = 0 + while True: + f = self.edit_area.find(str(text_list[-1]), flags) + if f is False: + break + my_text_cursor = self.edit_area.textCursor() + end_sel = my_text_cursor.selectionEnd() + + my_text_cursor.setPosition(start_sel) + my_text_cursor.setPosition(end_sel, QtGui.QTextCursor.KeepAnchor) + self.edit_area.setTextCursor(my_text_cursor) + + if 2 in sel_rows: + text_to_be_found = self.gcode_obj.gc_start + text_list = [x for x in text_to_be_found.split("\n") if x != ''] + + self.edit_area.find(str(text_list[0]), flags) + my_text_cursor = self.edit_area.textCursor() + start_sel = my_text_cursor.selectionStart() + + end_sel = 0 + while True: + f = self.edit_area.find(str(text_list[-1]), flags) + if f is False: + break + my_text_cursor = self.edit_area.textCursor() + end_sel = my_text_cursor.selectionEnd() + + my_text_cursor.setPosition(start_sel) + my_text_cursor.setPosition(end_sel, QtGui.QTextCursor.KeepAnchor) + self.edit_area.setTextCursor(my_text_cursor) + + for row in sel_rows: + # those are special rows treated before so we except them + if row not in [0, 1, 2]: + if self.gcode_obj.cnc_tools: + tool_no = int(t_table.item(row, 0).text()) + text_to_be_found = self.gcode_obj.cnc_tools[tool_no]['gcode'] + elif self.gcode_obj.exc_cnc_tools: + tool_dia = float(t_table.item(row, 1).text()) + text_to_be_found = self.gcode_obj.exc_cnc_tools[tool_dia]['gcode'] + else: + return + + text_list = [x for x in text_to_be_found.split("\n") if x != ''] + + self.edit_area.find(str(text_list[0]), flags) + my_text_cursor = self.edit_area.textCursor() + start_sel = my_text_cursor.selectionStart() + + end_sel = 0 + while True: + f = self.edit_area.find(str(text_list[-1]), flags) + if f is False: + break + my_text_cursor = self.edit_area.textCursor() + end_sel = my_text_cursor.selectionEnd() + + my_text_cursor.setPosition(start_sel) + my_text_cursor.setPosition(end_sel, QtGui.QTextCursor.KeepAnchor) + self.edit_area.setTextCursor(my_text_cursor) + + def on_toggle_all_rows(self): """ @@ -347,11 +442,13 @@ class AppGCodeEditor(QtCore.QObject): :rtype: """ if self.gcode_obj.cnc_tools: - sel_model = self.ui.cnc_tools_table.selectionModel() + t_table = self.ui.cnc_tools_table elif self.gcode_obj.exc_cnc_tools: - sel_model = self.ui.exc_cnc_tools_table.selectionModel() + t_table = self.ui.exc_cnc_tools_table else: return + + sel_model = t_table.selectionModel() sel_indexes = sel_model.selectedIndexes() # it will iterate over all indexes which means all items in all columns too but I'm interested only on rows @@ -359,18 +456,12 @@ class AppGCodeEditor(QtCore.QObject): for idx in sel_indexes: sel_rows.add(idx.row()) - if self.gcode_obj.cnc_tools: - if len(sel_rows) == self.ui.cnc_tools_table.rowCount(): - self.ui.cnc_tools_table.clearSelection() - else: - self.ui.cnc_tools_table.selectAll() - elif self.gcode_obj.exc_cnc_tools: - if len(sel_rows) == self.ui.exc_cnc_tools_table.rowCount(): - self.ui.exc_cnc_tools_table.clearSelection() - else: - self.ui.exc_cnc_tools_table.selectAll() + if len(sel_rows) == t_table.rowCount(): + t_table.clearSelection() + my_text_cursor = self.edit_area.textCursor() + my_text_cursor.clearSelection() else: - return + t_table.selectAll() def handleTextChanged(self): """ diff --git a/appGUI/ObjectUI.py b/appGUI/ObjectUI.py index da1859d1..9e1ef56f 100644 --- a/appGUI/ObjectUI.py +++ b/appGUI/ObjectUI.py @@ -1889,6 +1889,14 @@ class CNCObjectUI(ObjectUI): separator_line.setFrameShadow(QtWidgets.QFrame.Sunken) self.custom_box.addWidget(separator_line) + # CNC Code snippets + self.snippets_cb = FCCheckBox(_("Use CNC Code Snippets")) + self.snippets_cb.setToolTip( + _("When selected, it will include CNC Code snippets (append and prepend)\n" + "defined in the Preferences.") + ) + self.custom_box.addWidget(self.snippets_cb) + # #################### # ## Export G-Code ## # #################### @@ -1899,128 +1907,128 @@ class CNCObjectUI(ObjectUI): ) self.custom_box.addWidget(self.export_gcode_label) - # Prepend text to GCode - 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.custom_box.addWidget(prependlabel) - - self.prepend_text = FCTextArea() - self.prepend_text.setPlaceholderText( - _("Type here any G-Code commands you would\n" - "like to add at the beginning of the G-Code file.") - ) - self.custom_box.addWidget(self.prepend_text) - - # Append text to GCode - 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.custom_box.addWidget(appendlabel) - - 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.custom_box.addWidget(self.append_text) - - self.cnc_frame = QtWidgets.QFrame() - self.cnc_frame.setContentsMargins(0, 0, 0, 0) - self.custom_box.addWidget(self.cnc_frame) - self.cnc_box = QtWidgets.QVBoxLayout() - self.cnc_box.setContentsMargins(0, 0, 0, 0) - self.cnc_frame.setLayout(self.cnc_box) - - # Toolchange Custom G-Code - self.toolchangelabel = QtWidgets.QLabel('%s:' % _('Toolchange G-Code')) - self.toolchangelabel.setToolTip( - _( - "Type here any G-Code commands you would\n" - "like to be executed when Toolchange event is encountered.\n" - "This will constitute a Custom Toolchange GCode,\n" - "or a Toolchange Macro.\n" - "The FlatCAM variables are surrounded by '%' symbol.\n\n" - "WARNING: it can be used only with a preprocessor file\n" - "that has 'toolchange_custom' in it's name and this is built\n" - "having as template the 'Toolchange Custom' posprocessor file." - ) - ) - self.cnc_box.addWidget(self.toolchangelabel) - - self.toolchange_text = FCTextArea() - self.toolchange_text.setPlaceholderText( - _( - "Type here any G-Code commands you would\n" - "like to be executed when Toolchange event is encountered.\n" - "This will constitute a Custom Toolchange GCode,\n" - "or a Toolchange Macro.\n" - "The FlatCAM variables are surrounded by '%' symbol.\n" - "WARNING: it can be used only with a preprocessor file\n" - "that has 'toolchange_custom' in it's name." - ) - ) - self.cnc_box.addWidget(self.toolchange_text) - - cnclay = QtWidgets.QHBoxLayout() - self.cnc_box.addLayout(cnclay) - - # Toolchange Replacement Enable - self.toolchange_cb = FCCheckBox(label='%s' % _('Use Toolchange Macro')) - self.toolchange_cb.setToolTip( - _("Check this box if you want to use\n" - "a Custom Toolchange GCode (macro).") - ) - - # Variable list - self.tc_variable_combo = FCComboBox() - self.tc_variable_combo.setToolTip( - _( - "A list of the FlatCAM variables that can be used\n" - "in the Toolchange event.\n" - "They have to be surrounded by the '%' symbol" - ) - ) - - # Populate the Combo Box - variables = [_('Parameters'), 'tool', 'tooldia', 't_drills', 'x_toolchange', 'y_toolchange', 'z_toolchange', - 'z_cut', 'z_move', 'z_depthpercut', 'spindlespeed', 'dwelltime'] - self.tc_variable_combo.addItems(variables) - self.tc_variable_combo.setItemData(0, _("FlatCAM CNC parameters"), Qt.ToolTipRole) - self.tc_variable_combo.setItemData(1, "tool = " + _("tool number"), Qt.ToolTipRole) - self.tc_variable_combo.setItemData(2, "tooldia = " + _("tool diameter"), Qt.ToolTipRole) - self.tc_variable_combo.setItemData(3, "t_drills = " + _("for Excellon, total number of drills"), - Qt.ToolTipRole) - self.tc_variable_combo.setItemData(4, "x_toolchange = " + _("X coord for Toolchange"), Qt.ToolTipRole) - self.tc_variable_combo.setItemData(5, "y_toolchange = " + _("Y coord for Toolchange"), Qt.ToolTipRole) - self.tc_variable_combo.setItemData(6, "z_toolchange = " + _("Z coord for Toolchange"), Qt.ToolTipRole) - self.tc_variable_combo.setItemData(7, "z_cut = " + _("depth where to cut"), Qt.ToolTipRole) - self.tc_variable_combo.setItemData(8, "z_move = " + _("height where to travel"), Qt.ToolTipRole) - self.tc_variable_combo.setItemData(9, "z_depthpercut = " + _("the step value for multidepth cut"), - Qt.ToolTipRole) - self.tc_variable_combo.setItemData(10, "spindlesspeed = " + _("the value for the spindle speed"), - Qt.ToolTipRole) - self.tc_variable_combo.setItemData(11, "dwelltime = " + _("time to dwell to allow the " - "spindle to reach it's set RPM"), - Qt.ToolTipRole) - - cnclay.addWidget(self.toolchange_cb) - cnclay.addStretch() - cnclay.addWidget(self.tc_variable_combo) - - self.toolch_ois = OptionalInputSection(self.toolchange_cb, - [self.toolchangelabel, self.toolchange_text, self.tc_variable_combo]) - + # # Prepend text to GCode + # 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.custom_box.addWidget(prependlabel) + # + # self.prepend_text = FCTextArea() + # self.prepend_text.setPlaceholderText( + # _("Type here any G-Code commands you would\n" + # "like to add at the beginning of the G-Code file.") + # ) + # self.custom_box.addWidget(self.prepend_text) + # + # # Append text to GCode + # 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.custom_box.addWidget(appendlabel) + # + # 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.custom_box.addWidget(self.append_text) + # + # self.cnc_frame = QtWidgets.QFrame() + # self.cnc_frame.setContentsMargins(0, 0, 0, 0) + # self.custom_box.addWidget(self.cnc_frame) + # self.cnc_box = QtWidgets.QVBoxLayout() + # self.cnc_box.setContentsMargins(0, 0, 0, 0) + # self.cnc_frame.setLayout(self.cnc_box) + # + # # Toolchange Custom G-Code + # self.toolchangelabel = QtWidgets.QLabel('%s:' % _('Toolchange G-Code')) + # self.toolchangelabel.setToolTip( + # _( + # "Type here any G-Code commands you would\n" + # "like to be executed when Toolchange event is encountered.\n" + # "This will constitute a Custom Toolchange GCode,\n" + # "or a Toolchange Macro.\n" + # "The FlatCAM variables are surrounded by '%' symbol.\n\n" + # "WARNING: it can be used only with a preprocessor file\n" + # "that has 'toolchange_custom' in it's name and this is built\n" + # "having as template the 'Toolchange Custom' posprocessor file." + # ) + # ) + # self.cnc_box.addWidget(self.toolchangelabel) + # + # self.toolchange_text = FCTextArea() + # self.toolchange_text.setPlaceholderText( + # _( + # "Type here any G-Code commands you would\n" + # "like to be executed when Toolchange event is encountered.\n" + # "This will constitute a Custom Toolchange GCode,\n" + # "or a Toolchange Macro.\n" + # "The FlatCAM variables are surrounded by '%' symbol.\n" + # "WARNING: it can be used only with a preprocessor file\n" + # "that has 'toolchange_custom' in it's name." + # ) + # ) + # self.cnc_box.addWidget(self.toolchange_text) + # + # cnclay = QtWidgets.QHBoxLayout() + # self.cnc_box.addLayout(cnclay) + # + # # Toolchange Replacement Enable + # self.toolchange_cb = FCCheckBox(label='%s' % _('Use Toolchange Macro')) + # self.toolchange_cb.setToolTip( + # _("Check this box if you want to use\n" + # "a Custom Toolchange GCode (macro).") + # ) + # + # # Variable list + # self.tc_variable_combo = FCComboBox() + # self.tc_variable_combo.setToolTip( + # _( + # "A list of the FlatCAM variables that can be used\n" + # "in the Toolchange event.\n" + # "They have to be surrounded by the '%' symbol" + # ) + # ) + # + # # Populate the Combo Box + # variables = [_('Parameters'), 'tool', 'tooldia', 't_drills', 'x_toolchange', 'y_toolchange', 'z_toolchange', + # 'z_cut', 'z_move', 'z_depthpercut', 'spindlespeed', 'dwelltime'] + # self.tc_variable_combo.addItems(variables) + # self.tc_variable_combo.setItemData(0, _("FlatCAM CNC parameters"), Qt.ToolTipRole) + # self.tc_variable_combo.setItemData(1, "tool = " + _("tool number"), Qt.ToolTipRole) + # self.tc_variable_combo.setItemData(2, "tooldia = " + _("tool diameter"), Qt.ToolTipRole) + # self.tc_variable_combo.setItemData(3, "t_drills = " + _("for Excellon, total number of drills"), + # Qt.ToolTipRole) + # self.tc_variable_combo.setItemData(4, "x_toolchange = " + _("X coord for Toolchange"), Qt.ToolTipRole) + # self.tc_variable_combo.setItemData(5, "y_toolchange = " + _("Y coord for Toolchange"), Qt.ToolTipRole) + # self.tc_variable_combo.setItemData(6, "z_toolchange = " + _("Z coord for Toolchange"), Qt.ToolTipRole) + # self.tc_variable_combo.setItemData(7, "z_cut = " + _("depth where to cut"), Qt.ToolTipRole) + # self.tc_variable_combo.setItemData(8, "z_move = " + _("height where to travel"), Qt.ToolTipRole) + # self.tc_variable_combo.setItemData(9, "z_depthpercut = " + _("the step value for multidepth cut"), + # Qt.ToolTipRole) + # self.tc_variable_combo.setItemData(10, "spindlesspeed = " + _("the value for the spindle speed"), + # Qt.ToolTipRole) + # self.tc_variable_combo.setItemData(11, "dwelltime = " + _("time to dwell to allow the " + # "spindle to reach it's set RPM"), + # Qt.ToolTipRole) + # + # cnclay.addWidget(self.toolchange_cb) + # cnclay.addStretch() + # cnclay.addWidget(self.tc_variable_combo) + # + # self.toolch_ois = OptionalInputSection(self.toolchange_cb, + # [self.toolchangelabel, self.toolchange_text, self.tc_variable_combo]) + # h_lay = QtWidgets.QHBoxLayout() h_lay.setAlignment(QtCore.Qt.AlignVCenter) self.custom_box.addLayout(h_lay) - # + # # Edit GCode Button # self.modify_gcode_button = QtWidgets.QPushButton(_('View CNC Code')) # self.modify_gcode_button.setToolTip( @@ -2028,7 +2036,7 @@ class CNCObjectUI(ObjectUI): # "file.") # ) - # GO Button + # Save Button self.export_gcode_button = QtWidgets.QPushButton(_('Save CNC Code')) self.export_gcode_button.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png')) self.export_gcode_button.setToolTip( diff --git a/appObjects/FlatCAMCNCJob.py b/appObjects/FlatCAMCNCJob.py index 9fd26b27..9ddbcfbd 100644 --- a/appObjects/FlatCAMCNCJob.py +++ b/appObjects/FlatCAMCNCJob.py @@ -63,8 +63,8 @@ class CNCJobObject(FlatCAMObj, CNCjob): "dwell": False, "dwelltime": 1, "type": 'Geometry', - "toolchange_macro": '', - "toolchange_macro_enable": False + # "toolchange_macro": '', + # "toolchange_macro_enable": False }) ''' @@ -137,11 +137,6 @@ class CNCJobObject(FlatCAMObj, CNCjob): gcodenr_re_string = r'([+-]?\d*\.\d+)' self.g_nr_re = re.compile(gcodenr_re_string) - # Attributes to be included in serialization - # Always append to it because it carries contents - # from predecessors. - self.ser_attrs += ['options', 'kind', 'origin_kind', 'cnc_tools', 'exc_cnc_tools', 'multitool'] - if self.app.is_legacy is False: self.text_col = self.app.plotcanvas.new_text_collection() self.text_col.enabled = True @@ -152,6 +147,19 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.source_file = '' self.units_found = self.app.defaults['units'] + self.append_snippet = '' + self.prepend_snippet = '' + self.gc_header = self.gcode_header() + self.gc_start = '' + + # Attributes to be included in serialization + # Always append to it because it carries contents + # from predecessors. + self.ser_attrs += [ + 'options', 'kind', 'origin_kind', 'cnc_tools', 'exc_cnc_tools', 'multitool', 'append_snippet', + 'prepend_snippet', 'gc_header' + ] + def build_ui(self): self.ui_disconnect() @@ -364,17 +372,23 @@ class CNCJobObject(FlatCAMObj, CNCjob): # this signal has to be connected to it's slot before the defaults are populated # the decision done in the slot has to override the default value set below - self.ui.toolchange_cb.toggled.connect(self.on_toolchange_custom_clicked) + # self.ui.toolchange_cb.toggled.connect(self.on_toolchange_custom_clicked) self.form_fields.update({ "plot": self.ui.plot_cb, "tooldia": self.ui.tooldia_entry, - "append": self.ui.append_text, - "prepend": self.ui.prepend_text, - "toolchange_macro": self.ui.toolchange_text, - "toolchange_macro_enable": self.ui.toolchange_cb + # "append": self.ui.append_text, + # "prepend": self.ui.prepend_text, + # "toolchange_macro": self.ui.toolchange_text, + # "toolchange_macro_enable": self.ui.toolchange_cb }) + self.append_snippet = self.app.defaults['cncjob_append'] + self.prepend_snippet = self.app.defaults['cncjob_prepend'] + + if self.append_snippet != '' or self.prepend_snippet: + self.ui.snippets_cb.set_value(True) + # Fill form fields only on object create self.to_form() @@ -428,26 +442,31 @@ class CNCJobObject(FlatCAMObj, CNCjob): 'Basic' )) - self.ui.cnc_frame.hide() + # self.ui.cnc_frame.hide() else: self.ui.level.setText(_( 'Advanced' )) - self.ui.cnc_frame.show() + # self.ui.cnc_frame.show() self.ui.updateplot_button.clicked.connect(self.on_updateplot_button_click) self.ui.export_gcode_button.clicked.connect(self.on_exportgcode_button_click) self.ui.editor_button.clicked.connect(self.on_edit_code_click) - self.ui.tc_variable_combo.currentIndexChanged[str].connect(self.on_cnc_custom_parameters) + # self.ui.tc_variable_combo.currentIndexChanged[str].connect(self.on_cnc_custom_parameters) self.ui.cncplot_method_combo.activated_custom.connect(self.on_plot_kind_change) - def on_cnc_custom_parameters(self, signal_text): - if signal_text == 'Parameters': - return - else: - self.ui.toolchange_text.insertPlainText('%%%s%%' % signal_text) + preamble = self.append_snippet + postamble = self.prepend_snippet + gc = self.export_gcode(preamble=preamble, postamble=postamble, to_file=True) + self.source_file = gc.getvalue() + + # def on_cnc_custom_parameters(self, signal_text): + # if signal_text == 'Parameters': + # return + # else: + # self.ui.toolchange_text.insertPlainText('%%%s%%' % signal_text) def ui_connect(self): for row in range(self.ui.cnc_tools_table.rowCount()): @@ -525,6 +544,8 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.export_gcode_handler(filename, is_gcode=save_gcode) def export_gcode_handler(self, filename, is_gcode=True): + preamble = '' + postamble = '' filename = str(filename) if filename == '': @@ -540,8 +561,9 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.on_name_activate(silent=True) try: - preamble = str(self.ui.prepend_text.get_value()) - postamble = str(self.ui.append_text.get_value()) + if self.ui.snippets_cb.get_value(): + preamble = self.append_snippet + postamble = self.prepend_snippet gc = self.export_gcode(filename, preamble=preamble, postamble=postamble) except Exception as err: log.debug("CNCJobObject.export_gcode_handler() --> %s" % str(err)) @@ -565,8 +587,8 @@ class CNCJobObject(FlatCAMObj, CNCjob): self.app.proc_container.view.set_busy(_("Loading...")) - preamble = str(self.ui.prepend_text.get_value()) - postamble = str(self.ui.append_text.get_value()) + preamble = self.append_snippet + postamble = self.prepend_snippet gco = self.export_gcode(preamble=preamble, postamble=postamble, to_file=True) if gco == 'fail': @@ -622,6 +644,7 @@ class CNCJobObject(FlatCAMObj, CNCjob): marlin = False hpgl = False probe_pp = False + gcode = '' start_comment = comment_start_symbol if comment_start_symbol is not None else '(' stop_comment = comment_stop_symbol if comment_stop_symbol is not None else ')' @@ -657,8 +680,8 @@ class CNCJobObject(FlatCAMObj, CNCjob): pass if marlin is True: - gcode = ';Marlin(Repetier) G-CODE GENERATED BY FLATCAM v%s - www.flatcam.org - Version Date: %s\n' % \ - (str(self.app.version), str(self.app.version_date)) + '\n' + gcode += ';Marlin(Repetier) G-CODE GENERATED BY FLATCAM v%s - www.flatcam.org - Version Date: %s\n' % \ + (str(self.app.version), str(self.app.version_date)) + '\n' gcode += ';Name: ' + str(self.options['name']) + '\n' gcode += ';Type: ' + "G-code from " + str(self.options['type']) + '\n' @@ -669,8 +692,8 @@ class CNCJobObject(FlatCAMObj, CNCjob): gcode += ';Units: ' + self.units.upper() + '\n' + "\n" gcode += ';Created on ' + time_str + '\n' + '\n' elif hpgl is True: - gcode = 'CO "HPGL CODE GENERATED BY FLATCAM v%s - www.flatcam.org - Version Date: %s' % \ - (str(self.app.version), str(self.app.version_date)) + '";\n' + gcode += 'CO "HPGL CODE GENERATED BY FLATCAM v%s - www.flatcam.org - Version Date: %s' % \ + (str(self.app.version), str(self.app.version_date)) + '";\n' gcode += 'CO "Name: ' + str(self.options['name']) + '";\n' gcode += 'CO "Type: ' + "HPGL code from " + str(self.options['type']) + '";\n' @@ -681,8 +704,8 @@ class CNCJobObject(FlatCAMObj, CNCjob): gcode += 'CO "Units: ' + self.units.upper() + '";\n' gcode += 'CO "Created on ' + time_str + '";\n' elif probe_pp is True: - gcode = '(G-CODE GENERATED BY FLATCAM v%s - www.flatcam.org - Version Date: %s)\n' % \ - (str(self.app.version), str(self.app.version_date)) + '\n' + gcode += '(G-CODE GENERATED BY FLATCAM v%s - www.flatcam.org - Version Date: %s)\n' % \ + (str(self.app.version), str(self.app.version_date)) + '\n' gcode += '(This GCode tool change is done by using a Probe.)\n' \ '(Make sure that before you start the job you first do a rough zero for Z axis.)\n' \ @@ -699,8 +722,8 @@ class CNCJobObject(FlatCAMObj, CNCjob): gcode += '(Units: ' + self.units.upper() + ')\n' + "\n" gcode += '(Created on ' + time_str + ')\n' + '\n' else: - gcode = '%sG-CODE GENERATED BY FLATCAM v%s - www.flatcam.org - Version Date: %s%s\n' % \ - (start_comment, str(self.app.version), str(self.app.version_date), stop_comment) + '\n' + gcode += '%sG-CODE GENERATED BY FLATCAM v%s - www.flatcam.org - Version Date: %s%s\n' % \ + (start_comment, str(self.app.version), str(self.app.version_date), stop_comment) + '\n' gcode += '%sName: ' % start_comment + str(self.options['name']) + '%s\n' % stop_comment gcode += '%sType: ' % start_comment + "G-code from " + str(self.options['type']) + '%s\n' % stop_comment @@ -847,31 +870,40 @@ class CNCJobObject(FlatCAMObj, CNCjob): processed_gcode += gline + '\n' gcode = processed_gcode - g = self.gcode_header() + '\n' + preamble + '\n' + gcode + postamble + end_gcode + g = self.gc_header + '\n' + preamble + '\n' + gcode + postamble + end_gcode else: try: g_idx = gcode.index('G94') - g = self.gcode_header() + gcode[:g_idx + 3] + '\n\n' + preamble + '\n' + \ - gcode[(g_idx + 3):] + postamble + end_gcode + if preamble != '' and postamble != '': + g = self.gc_header + gcode[:g_idx + 3] + '\n' + preamble + '\n' + \ + gcode[(g_idx + 3):] + postamble + end_gcode + elif preamble == '': + g = self.gc_header + gcode[:g_idx + 3] + '\n' + \ + gcode[(g_idx + 3):] + postamble + end_gcode + elif postamble == '': + g = self.gc_header + gcode[:g_idx + 3] + '\n' + preamble + '\n' + \ + gcode[(g_idx + 3):] + end_gcode + else: + g = self.gc_header + gcode[:g_idx + 3] + gcode[(g_idx + 3):] + end_gcode except ValueError: self.app.inform.emit('[ERROR_NOTCL] %s' % - _("G-code does not have a G94 code and we will not include the code in the " - "'Prepend to GCode' text box")) - g = self.gcode_header() + '\n' + gcode + postamble + end_gcode + _("G-code does not have a G94 code.\n" + "Append Code snippet will not be used..")) + g = self.gc_header + '\n' + gcode + postamble + end_gcode # if toolchange custom is used, replace M6 code with the code from the Toolchange Custom Text box - if self.ui.toolchange_cb.get_value() is True: - # match = self.re_toolchange.search(g) - if 'M6' in g: - m6_code = self.parse_custom_toolchange_code(self.ui.toolchange_text.get_value()) - if m6_code is None or m6_code == '': - self.app.inform.emit( - '[ERROR_NOTCL] %s' % _("Cancelled. The Toolchange Custom code is enabled but it's empty.") - ) - return 'fail' - - g = g.replace('M6', m6_code) - self.app.inform.emit('[success] %s' % _("Toolchange G-code was replaced by a custom code.")) + # if self.ui.toolchange_cb.get_value() is True: + # # match = self.re_toolchange.search(g) + # if 'M6' in g: + # m6_code = self.parse_custom_toolchange_code(self.ui.toolchange_text.get_value()) + # if m6_code is None or m6_code == '': + # self.app.inform.emit( + # '[ERROR_NOTCL] %s' % _("Cancelled. The Toolchange Custom code is enabled but it's empty.") + # ) + # return 'fail' + # + # g = g.replace('M6', m6_code) + # self.app.inform.emit('[success] %s' % _("Toolchange G-code was replaced by a custom code.")) lines = StringIO(g) @@ -906,32 +938,32 @@ class CNCJobObject(FlatCAMObj, CNCjob): else: return lines - def on_toolchange_custom_clicked(self, signal): - """ - Handler for clicking toolchange custom. - - :param signal: - :return: - """ - - try: - if 'toolchange_custom' not in str(self.options['ppname_e']).lower(): - if self.ui.toolchange_cb.get_value(): - self.ui.toolchange_cb.set_value(False) - self.app.inform.emit('[WARNING_NOTCL] %s' % - _("The used preprocessor file has to have in it's name: 'toolchange_custom'")) - except KeyError: - try: - for key in self.cnc_tools: - ppg = self.cnc_tools[key]['data']['ppname_g'] - if 'toolchange_custom' not in str(ppg).lower(): - if self.ui.toolchange_cb.get_value(): - self.ui.toolchange_cb.set_value(False) - self.app.inform.emit('[WARNING_NOTCL] %s' % - _("The used preprocessor file has to have in it's name: " - "'toolchange_custom'")) - except KeyError: - self.app.inform.emit('[ERROR] %s' % _("There is no preprocessor file.")) + # def on_toolchange_custom_clicked(self, signal): + # """ + # Handler for clicking toolchange custom. + # + # :param signal: + # :return: + # """ + # + # try: + # if 'toolchange_custom' not in str(self.options['ppname_e']).lower(): + # if self.ui.toolchange_cb.get_value(): + # self.ui.toolchange_cb.set_value(False) + # self.app.inform.emit('[WARNING_NOTCL] %s' % + # _("The used preprocessor file has to have in it's name: 'toolchange_custom'")) + # except KeyError: + # try: + # for key in self.cnc_tools: + # ppg = self.cnc_tools[key]['data']['ppname_g'] + # if 'toolchange_custom' not in str(ppg).lower(): + # if self.ui.toolchange_cb.get_value(): + # self.ui.toolchange_cb.set_value(False) + # self.app.inform.emit('[WARNING_NOTCL] %s' % + # _("The used preprocessor file has to have in it's name: " + # "'toolchange_custom'")) + # except KeyError: + # self.app.inform.emit('[ERROR] %s' % _("There is no preprocessor file.")) def get_gcode(self, preamble='', postamble=''): """ diff --git a/appObjects/FlatCAMGeometry.py b/appObjects/FlatCAMGeometry.py index 7c85b45b..28423caf 100644 --- a/appObjects/FlatCAMGeometry.py +++ b/appObjects/FlatCAMGeometry.py @@ -2109,21 +2109,14 @@ class GeometryObject(FlatCAMObj, Geometry): # 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 tol = float(self.app.defaults['global_tolerance']) / 20 - # res = job_obj.generate_from_multitool_geometry( - # tool_solid_geometry, tooldia=tooldia_val, offset=tool_offset, - # tolerance=tol, z_cut=z_cut, z_move=z_move, - # feedrate=feedrate, feedrate_z=feedrate_z, feedrate_rapid=feedrate_rapid, - # spindlespeed=spindlespeed, spindledir=spindledir, dwell=dwell, dwelltime=dwelltime, - # multidepth=multidepth, depthpercut=depthpercut, - # extracut=extracut, extracut_length=extracut_length, startz=startz, endz=endz, endxy=endxy, - # toolchange=toolchange, toolchangez=toolchangez, toolchangexy=toolchangexy, - # pp_geometry_name=pp_geometry_name, - # tool_no=tool_cnt) + tool_lst = list(tools_dict.keys()) is_first = True if tooluid_key == tool_lst[0] else False is_last = True if tooluid_key == tool_lst[-1] else False - res = job_obj.geometry_tool_gcode_gen(tooluid_key, tools_dict, first_pt=(0, 0), tolerance = tol, - is_first=is_first, is_last=is_last, toolchange = True) + res, start_gcode = job_obj.geometry_tool_gcode_gen(tooluid_key, tools_dict, first_pt=(0, 0), + tolerance = tol, + is_first=is_first, is_last=is_last, + toolchange = True) if res == 'fail': log.debug("GeometryObject.mtool_gen_cncjob() --> generate_from_geometry2() failed") return 'fail' @@ -2131,6 +2124,9 @@ class GeometryObject(FlatCAMObj, Geometry): dia_cnc_dict['gcode'] = res total_gcode += res + if start_gcode != '': + job_obj.gc_start = start_gcode + self.app.inform.emit('[success] %s' % _("G-Code parsing in progress...")) dia_cnc_dict['gcode_parsed'] = job_obj.gcode_parse() self.app.inform.emit('[success] %s' % _("G-Code parsing finished...")) diff --git a/appTools/ToolDrilling.py b/appTools/ToolDrilling.py index f5b061bc..763ea1c4 100644 --- a/appTools/ToolDrilling.py +++ b/appTools/ToolDrilling.py @@ -1725,12 +1725,13 @@ class ToolDrilling(AppTool, Excellon): job_obj.options['Tools_in_use'] = tool_table_items # generate GCode - tool_gcode, __ = job_obj.excellon_tool_gcode_gen(used_tool, tool_points, self.excellon_tools, - first_pt=first_drill_point, - is_first=True, - is_last=True, - opt_type=used_excellon_optimization_type, - toolchange=True) + tool_gcode, __, start_gcode = job_obj.excellon_tool_gcode_gen(used_tool, tool_points, + self.excellon_tools, + first_pt=first_drill_point, + is_first=True, + is_last=True, + opt_type=used_excellon_optimization_type, + toolchange=True) # parse the Gcode tool_gcode_parsed = job_obj.excellon_tool_gcode_parse(used_tooldia, gcode=tool_gcode, @@ -1748,6 +1749,9 @@ class ToolDrilling(AppTool, Excellon): if e_tool_dia != used_tooldia: job_obj.exc_cnc_tools.pop(e_tool_dia, None) + if start_gcode != '': + job_obj.gc_start = start_gcode + self.total_gcode = tool_gcode self.total_gcode_parsed = tool_gcode_parsed @@ -1778,12 +1782,13 @@ class ToolDrilling(AppTool, Excellon): is_first_tool = True if tool == sel_tools[0] else False # Generate Gcode for the current tool - tool_gcode, last_pt = job_obj.excellon_tool_gcode_gen(tool, tool_points, self.excellon_tools, - first_pt=first_drill_point, - is_first=is_first_tool, - is_last=is_last_tool, - opt_type=used_excellon_optimization_type, - toolchange=True) + tool_gcode, last_pt, start_gcode = job_obj.excellon_tool_gcode_gen( + tool, tool_points, self.excellon_tools, + first_pt=first_drill_point, + is_first=is_first_tool, + is_last=is_last_tool, + opt_type=used_excellon_optimization_type, + toolchange=True) # parse Gcode for the current tool tool_gcode_parsed = job_obj.excellon_tool_gcode_parse(used_tooldia, gcode=tool_gcode, @@ -1794,6 +1799,9 @@ class ToolDrilling(AppTool, Excellon): job_obj.exc_cnc_tools[used_tooldia]['gcode'] = tool_gcode job_obj.exc_cnc_tools[used_tooldia]['gcode_parsed'] = tool_gcode_parsed + if start_gcode != '': + job_obj.gc_start = start_gcode + self.total_gcode += tool_gcode self.total_gcode_parsed += tool_gcode_parsed diff --git a/app_Main.py b/app_Main.py index ac6a02d7..543ba82e 100644 --- a/app_Main.py +++ b/app_Main.py @@ -2238,7 +2238,6 @@ class App(QtCore.QObject): self.call_source = 'gcode_editor' self.gcode_editor.edit_fcgcode(edited_object) - return # make sure that we can't select another object while in Editor Mode: # self.collection.view.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection) @@ -2379,7 +2378,12 @@ class App(QtCore.QObject): # restore GUI to the Selected TAB # Remove anything else in the GUI self.ui.tool_scroll_area.takeWidget() + edited_obj.build_ui() + # close the open tab + for idx in range(self.ui.plot_tab_area.count()): + if self.ui.plot_tab_area.widget(idx).objectName() == 'gcode_editor_tab': + self.ui.plot_tab_area.closeTab(idx) self.inform.emit('[success] %s' % _("Editor exited. Editor content saved.")) else: @@ -2413,6 +2417,11 @@ class App(QtCore.QObject): edited_obj.build_ui() elif edited_obj.kind == 'cncjob': edited_obj.build_ui() + + # close the open tab + for idx in range(self.ui.plot_tab_area.count()): + if self.ui.plot_tab_area.widget(idx).objectName() == 'gcode_editor_tab': + self.ui.plot_tab_area.closeTab(idx) else: self.inform.emit('[WARNING_NOTCL] %s' % _("Select a Gerber, Geometry, Excellon or CNCJobObject to update.")) diff --git a/camlib.py b/camlib.py index 10217cd9..9104248b 100644 --- a/camlib.py +++ b/camlib.py @@ -2980,7 +2980,8 @@ class CNCjob(Geometry): - :return: A tuple made from tool_gcode and another tuple holding the coordinates of the last point + :return: A tuple made from tool_gcode, another tuple holding the coordinates of the last point + and the start gcode :rtype: tuple """ log.debug("Creating CNC Job from Excellon for tool: %s" % str(tool)) @@ -3153,8 +3154,9 @@ class CNCjob(Geometry): # graceful abort requested by the user raise grace - start_gcode = self.doformat(p.start_code) + start_gcode = '' if is_first: + start_gcode = self.doformat(p.start_code) t_gcode += start_gcode # do the ToolChange event @@ -3305,7 +3307,7 @@ class CNCjob(Geometry): t_gcode += self.doformat(p.end_code, x=0, y=0) self.app.inform.emit(_("Finished G-Code generation for tool: %s" % str(tool))) - return t_gcode, (locx, locy) + return t_gcode, (locx, locy), start_gcode def generate_from_excellon_by_tool(self, exobj, tools="all", order='fwd', use_ui=False): """ @@ -5280,8 +5282,10 @@ class CNCjob(Geometry): total_cut = 0.0 # Start GCode + start_gcode = '' if is_first: - t_gcode += self.doformat(p.start_code) + start_gcode = self.doformat(p.start_code) + t_gcode += start_gcode # Toolchange code t_gcode += self.doformat(p.feedrate_code) # sets the feed rate @@ -5379,7 +5383,7 @@ class CNCjob(Geometry): ) self.gcode = t_gcode - return self.gcode + return self.gcode, start_gcode def generate_from_geometry_2(self, geometry, append=True, tooldia=None, offset=0.0, tolerance=0, z_cut=None, z_move=None, feedrate=None, feedrate_z=None, feedrate_rapid=None, spindlespeed=None,