diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3cc03f8d..cce3b54a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,15 @@ CHANGELOG for FlatCAM beta
=================================================
+20.12.2020
+
+- modified the way the status bar icon is set
+- Drilling Tool - fixed missing feedrate code when the toolchange is Off
+- AppTextEditor - working on syntax highlighting
+- App - trying to speed up the new project creation
+- Tcl Shell - Browser Edit - added Undo/Redo, Cut and Delete selection
+- replace all the exec_() calls with exec() (except one situation in Tcl where I'm not sure of the effect)
+
18.12.2020
- fixed the Tcl command export_gcode to return the actual gcode
@@ -5433,7 +5442,7 @@ saving an Excellon object from editor to FlatCAM, selecting drills by left click
19.09.2018
-- optimized loading FlatCAM project by double clicking on project file; there is no need to clean up everything by using the function not Thread Safe: on_file_new() because there is nothing to clean since FlatCAM just started.
+- optimized loading FlatCAM project by double clicking on project file; there is no need to clean up everything by using the function not Thread Safe: on_file_new_project() because there is nothing to clean since FlatCAM just started.
- added a workspace delimitation with sizes A3, A4 and landscape or portrait format
- The Workspace checkbox in Preferences GUI is doing toggle on the workspace
diff --git a/appEditors/AppTextEditor.py b/appEditors/AppTextEditor.py
index 8de4f807..387ceaea 100644
--- a/appEditors/AppTextEditor.py
+++ b/appEditors/AppTextEditor.py
@@ -25,9 +25,11 @@ if '_' not in builtins.__dict__:
class AppTextEditor(QtWidgets.QWidget):
- def __init__(self, app, text=None, plain_text=None, parent=None):
+ def __init__(self, app, text=None, plain_text=None, color_dict=None, parent=None):
super().__init__(parent=parent)
+ if color_dict is None:
+ color_dict = {}
self.app = app
self.plain_text = plain_text
self.callback = lambda x: None
@@ -51,7 +53,7 @@ class AppTextEditor(QtWidgets.QWidget):
# CODE Editor
if self.plain_text:
- self.editor_class = FCTextAreaLineNumber()
+ self.editor_class = FCTextAreaLineNumber(color_dict=color_dict)
self.code_editor = self.editor_class.edit
stylesheet = """
diff --git a/appGUI/GUIElements.py b/appGUI/GUIElements.py
index ebb07b16..53c4952d 100644
--- a/appGUI/GUIElements.py
+++ b/appGUI/GUIElements.py
@@ -1901,7 +1901,7 @@ class FCPlainTextAreaExtended(QtWidgets.QPlainTextEdit):
self.menu.addSeparator()
# CUT
- self. cut_action = QAction('%s\t%s' % (_("Cut"), _('Ctrl+X')), self)
+ self.cut_action = QAction('%s\t%s' % (_("Cut"), _('Ctrl+X')), self)
self.menu.addAction(self.cut_action)
self.cut_action.triggered.connect(self.cut_text)
@@ -2368,7 +2368,7 @@ class FCInputDoubleSpinner(QtWidgets.QDialog):
self.wdg.set_value(val)
def get_value(self):
- if self.exec_() == QtWidgets.QDialog.Accepted:
+ if self.exec() == QtWidgets.QDialog.Accepted:
return self.wdg.get_value(), True
else:
return None, False
@@ -2435,7 +2435,7 @@ class FCInputSpinner(QtWidgets.QDialog):
self.wdg.spinner.set_step(val)
def get_value(self):
- if self.exec_() == QtWidgets.QDialog.Accepted:
+ if self.exec() == QtWidgets.QDialog.Accepted:
return [self.wdg.get_value(), True]
else:
return [None, False]
@@ -2496,7 +2496,7 @@ class FCInputDialogSlider(QtWidgets.QDialog):
self.wdg.spinner.set_step(val)
def get_results(self):
- if self.exec_() == QtWidgets.QDialog.Accepted:
+ if self.exec() == QtWidgets.QDialog.Accepted:
return self.wdg.get_value(), True
else:
return None, False
@@ -2567,7 +2567,7 @@ class FCInputDialogSpinnerButton(QtWidgets.QDialog):
self.wdg.spinner.set_value(val)
def get_results(self):
- if self.exec_() == QtWidgets.QDialog.Accepted:
+ if self.exec() == QtWidgets.QDialog.Accepted:
return self.wdg.get_value(), True
else:
return None, False
@@ -3751,8 +3751,8 @@ class FCTable(QtWidgets.QTableWidget):
elif rect.bottom() - pos.y() < margin:
return True
# noinspection PyTypeChecker
- return rect.contains(pos, True) and not (int(self.model().flags(index)) & Qt.ItemIsDropEnabled) and \
- pos.y() >= rect.center().y()
+ drop_enabled = int(self.model().flags(index)) & Qt.ItemIsDropEnabled
+ return rect.contains(pos, True) and not drop_enabled and pos.y() >= rect.center().y()
class SpinBoxDelegate(QtWidgets.QItemDelegate):
@@ -3898,7 +3898,7 @@ class DialogBoxRadio(QtWidgets.QDialog):
self.readyToEdit = True
- if self.exec_() == QtWidgets.QDialog.Accepted:
+ if self.exec() == QtWidgets.QDialog.Accepted:
self.ok = True
self.location = self.lineEdit.text()
self.reference = self.ref_radio.get_value()
@@ -3915,46 +3915,104 @@ class _BrowserTextEdit(QTextEdit):
self.app = app
self.find_text = lambda: None
- def contextMenuEvent(self, event):
- # self.menu = self.createStandardContextMenu(event.pos())
+ self.isUndoAvailable = False
+ self.isRedoAvailable = False
+
+ # Context Menu Construction
self.menu = QtWidgets.QMenu()
- tcursor = self.textCursor()
- txt = tcursor.selectedText()
- copy_action = QAction('%s\t%s' % (_("Copy"), _('Ctrl+C')), self)
- self.menu.addAction(copy_action)
- copy_action.triggered.connect(self.copy_text)
- if txt == '':
- copy_action.setDisabled(True)
+ # UNDO
+ self.undo_action = QAction('%s\t%s' % (_("Undo"), _('Ctrl+Z')), self)
+ self.menu.addAction(self.undo_action)
+ self.undo_action.triggered.connect(self.undo)
+
+ # REDO
+ self.redo_action = QAction('%s\t%s' % (_("Redo"), _('Ctrl+Y')), self)
+ self.menu.addAction(self.redo_action)
+ self.redo_action.triggered.connect(self.redo)
self.menu.addSeparator()
- sel_all_action = QAction('%s\t%s' % (_("Select All"), _('Ctrl+A')), self)
- self.menu.addAction(sel_all_action)
- sel_all_action.triggered.connect(self.selectAll)
+ # CUT
+ self.cut_action = QAction('%s\t%s' % (_("Cut"), _('Ctrl+X')), self)
+ self.menu.addAction(self.cut_action)
+ self.cut_action.triggered.connect(self.cut_text)
- find_action = QAction('%s\t%s' % (_("Find"), _('Ctrl+F')), self)
- self.menu.addAction(find_action)
- find_action.triggered.connect(self.find_text)
+ # Copy
+ self.copy_action = QAction('%s\t%s' % (_("Copy"), _('Ctrl+C')), self)
+ self.menu.addAction(self.copy_action)
+ self.copy_action.triggered.connect(self.copy_text)
+
+ # Delete
+ self.delete_action = QAction('%s\t%s' % (_("Delete"), _('Del')), self)
+ self.menu.addAction(self.delete_action)
+ self.delete_action.triggered.connect(self.delete_text)
self.menu.addSeparator()
+ # Select All
+ self.sel_all_action = QAction('%s\t%s' % (_("Select All"), _('Ctrl+A')), self)
+ self.menu.addAction(self.sel_all_action)
+ self.sel_all_action.triggered.connect(self.selectAll)
+
+ # Find
+ self.find_action = QAction('%s\t%s' % (_("Find"), _('Ctrl+F')), self)
+ self.menu.addAction(self.find_action)
+ self.find_action.triggered.connect(self.find_text)
+
+ self.menu.addSeparator()
+
+ # Save
if self.app:
- save_action = QAction('%s\t%s' % (_("Save Log"), _('Ctrl+S')), self)
+ self.save_action = QAction('%s\t%s' % (_("Save Log"), _('Ctrl+S')), self)
# save_action.setShortcut(QKeySequence(Qt.Key_S))
- self.menu.addAction(save_action)
- save_action.triggered.connect(lambda: self.save_log(app=self.app))
+ self.menu.addAction(self.save_action)
+ self.save_action.triggered.connect(lambda: self.save_log(app=self.app))
- clear_action = QAction('%s\t%s' % (_("Clear All"), _('Del')), self)
+ # Clear
+ self.clear_action = QAction('%s\t%s' % (_("Clear All"), _('Shift+Del')), self)
# clear_action.setShortcut(QKeySequence(Qt.Key_Delete))
- self.menu.addAction(clear_action)
- clear_action.triggered.connect(self.clear)
+ self.menu.addAction(self.clear_action)
+ self.clear_action.triggered.connect(self.clear)
+ # Close the Dock
# if self.app:
# close_action = QAction(_("Close"), self)
# self.menu.addAction(close_action)
# close_action.triggered.connect(lambda: self.app.ui.shell_dock.hide())
+ # Signals
+ self.undoAvailable.connect(self.on_undo_available)
+ self.redoAvailable.connect(self.on_redo_available)
+
+ def on_undo_available(self, state):
+ self.isUndoAvailable = state
+
+ def on_redo_available(self, state):
+ self.isRedoAvailable = state
+
+ def contextMenuEvent(self, event):
+ # self.menu = self.createStandardContextMenu(event.pos())
+ tcursor = self.textCursor()
+ txt = tcursor.selectedText()
+
+ if self.isUndoAvailable is True:
+ self.undo_action.setDisabled(False)
+ else:
+ self.undo_action.setDisabled(True)
+
+ if self.isRedoAvailable is True:
+ self.redo_action.setDisabled(False)
+ else:
+ self.redo_action.setDisabled(True)
+
+ if txt == '':
+ self.cut_action.setDisabled(True)
+ self.copy_action.setDisabled(True)
+ else:
+ self.cut_action.setDisabled(False)
+ self.copy_action.setDisabled(False)
+
self.menu.exec_(event.globalPos())
def keyPressEvent(self, event) -> None:
@@ -3968,18 +4026,34 @@ class _BrowserTextEdit(QTextEdit):
# Copy Text
elif key == QtCore.Qt.Key_C:
self.copy_text()
- # Copy Text
+ # Find Text
elif key == QtCore.Qt.Key_F:
self.find_text()
# Save Log
elif key == QtCore.Qt.Key_S:
if self.app:
self.save_log(app=self.app)
+ # Cut Text
+ elif key == QtCore.Qt.Key_X:
+ self.cut_text()
+ # Undo Text
+ elif key == QtCore.Qt.Key_Z:
+ if self.isUndoAvailable:
+ self.undo()
+ # Redo Text
+ elif key == QtCore.Qt.Key_Y:
+ if self.isRedoAvailable:
+ self.redo()
+
+ if modifiers == QtCore.Qt.ShiftModifier:
+ # Clear all
+ if key == QtCore.Qt.Key_Delete:
+ self.clear()
elif modifiers == QtCore.Qt.NoModifier:
# Clear all
if key == QtCore.Qt.Key_Delete:
- self.clear()
+ self.delete_text()
# Shell toggle
if key == QtCore.Qt.Key_S:
self.app.ui.toggle_shell_ui()
@@ -3992,6 +4066,26 @@ class _BrowserTextEdit(QTextEdit):
clipboard.clear()
clipboard.setText(txt)
+ def cut_text(self):
+ tcursor = self.textCursor()
+ clipboard = QtWidgets.QApplication.clipboard()
+
+ txt = tcursor.selectedText()
+ clipboard.clear()
+ clipboard.setText(txt)
+
+ tcursor.removeSelectedText()
+
+ def delete_text(self):
+ tcursor = self.textCursor()
+ txt = tcursor.selectedText()
+ if txt == '':
+ tcursor.deleteChar()
+ else:
+ tcursor.removeSelectedText()
+
+ self.setTextCursor(tcursor)
+
def clear(self):
QTextEdit.clear(self)
@@ -4209,15 +4303,163 @@ class FCTextAreaLineNumber(QtWidgets.QFrame):
and from here: https://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html
"""
- def __init__(self, *args):
+ def __init__(self, *args, color_dict=None):
FCPlainTextAreaExtended.__init__(self, *args)
+ self.color_storage = color_dict if color_dict else {}
+
# self.setFrameStyle(QFrame.NoFrame)
self.setFrameStyle(QtWidgets.QFrame.NoFrame)
self.highlight()
# self.setLineWrapMode(QPlainTextEdit.NoWrap)
self.cursorPositionChanged.connect(self.highlight)
+ self.highlighter = self.MyHighlighter(self.document())
+
+ class MyHighlighter(QtGui.QSyntaxHighlighter):
+
+ def __init__(self, parent, highlight_rules=None):
+ QtGui.QSyntaxHighlighter.__init__(self, parent)
+ self.parent = parent
+ self.highlightingRules = []
+
+ if highlight_rules is None:
+ reservedClasses = QtGui.QTextCharFormat()
+ parameterOperator = QtGui.QTextCharFormat()
+ delimiter = QtGui.QTextCharFormat()
+ specialConstant = QtGui.QTextCharFormat()
+ boolean = QtGui.QTextCharFormat()
+ number = QtGui.QTextCharFormat()
+ string = QtGui.QTextCharFormat()
+ singleQuotedString = QtGui.QTextCharFormat()
+
+ comment = QtGui.QTextCharFormat()
+ # comment
+ brush = QtGui.QBrush(Qt.gray, Qt.SolidPattern)
+ pattern = QtCore.QRegExp("\(.*\)")
+ comment.setForeground(brush)
+ rule = (pattern, comment)
+ self.highlightingRules.append(rule)
+
+ # Marlin comment
+ brush = QtGui.QBrush(Qt.gray, Qt.SolidPattern)
+ pattern = QtCore.QRegExp("^;\s*.*$")
+ comment.setForeground(brush)
+ rule = (pattern, comment)
+ self.highlightingRules.append(rule)
+
+ # Python comment
+ brush = QtGui.QBrush(Qt.gray, Qt.SolidPattern)
+ pattern = QtCore.QRegExp("^\#\s*.*$")
+ comment.setForeground(brush)
+ rule = (pattern, comment)
+ self.highlightingRules.append(rule)
+
+ keyword = QtGui.QTextCharFormat()
+ # keyword
+ brush = QtGui.QBrush(Qt.blue, Qt.SolidPattern)
+ keyword.setForeground(brush)
+ keyword.setFontWeight(QtGui.QFont.Bold)
+ keywords = ["F", "G", "M", "T"]
+ for word in keywords:
+ # pattern = QtCore.QRegExp("\\b" + word + "\\b")
+ pattern = QtCore.QRegExp("\\b" + word + "\d+(\.\d*)?\s?" + "\\b")
+ rule = (pattern, keyword)
+ self.highlightingRules.append(rule)
+
+ # reservedClasses
+ reservedClasses.setForeground(brush)
+ reservedClasses.setFontWeight(QtGui.QFont.Bold)
+ keywords = ["array", "character", "complex", "data.frame", "double", "factor",
+ "function", "integer", "list", "logical", "matrix", "numeric", "vector"]
+ for word in keywords:
+ pattern = QtCore.QRegExp("\\b" + word + "\\b")
+ rule = (pattern, reservedClasses)
+ self.highlightingRules.append(rule)
+
+ # parameter
+ brush = QtGui.QBrush(Qt.darkBlue, Qt.SolidPattern)
+ pattern = QtCore.QRegExp("\-[0-9a-zA-Z]*\s")
+ parameterOperator.setForeground(brush)
+ parameterOperator.setFontWeight(QtGui.QFont.Bold)
+ rule = (pattern, parameterOperator)
+ self.highlightingRules.append(rule)
+
+ # delimiter
+ pattern = QtCore.QRegExp("[\)\(]+|[\{\}]+|[][]+")
+ delimiter.setForeground(brush)
+ delimiter.setFontWeight(QtGui.QFont.Bold)
+ rule = (pattern, delimiter)
+ self.highlightingRules.append(rule)
+
+ # specialConstant
+ brush = QtGui.QBrush(Qt.green, Qt.SolidPattern)
+ specialConstant.setForeground(brush)
+ keywords = ["Inf", "NA", "NaN", "NULL"]
+ for word in keywords:
+ pattern = QtCore.QRegExp("\\b" + word + "\\b")
+ rule = (pattern, specialConstant)
+ self.highlightingRules.append(rule)
+
+ # boolean
+ boolean.setForeground(brush)
+ keywords = ["TRUE", "True","FALSE", "False"]
+ for word in keywords:
+ pattern = QtCore.QRegExp("\\b" + word + "\\b")
+ rule = (pattern, boolean)
+ self.highlightingRules.append(rule)
+
+ # number
+ # pattern = QtCore.QRegExp("[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?")
+ # pattern.setMinimal(True)
+ # number.setForeground(brush)
+ # rule = (pattern, number)
+ # self.highlightingRules.append(rule)
+
+ # string
+ brush = QtGui.QBrush(Qt.red, Qt.SolidPattern)
+ pattern = QtCore.QRegExp("\".*\"")
+ pattern.setMinimal(True)
+ string.setForeground(brush)
+ rule = (pattern, string)
+ self.highlightingRules.append(rule)
+
+ # singleQuotedString
+ pattern = QtCore.QRegExp("\'.*\'")
+ pattern.setMinimal(True)
+ singleQuotedString.setForeground(brush)
+ rule = (pattern, singleQuotedString)
+ self.highlightingRules.append(rule)
+ else:
+ self.highlightingRules = highlight_rules
+
+ def highlightBlock(self, text):
+ """
+
+ :param text: string
+ :type text: str
+ :return:
+ :rtype:
+ """
+
+ # go in reverse from the last element to the first
+ for rule in self.highlightingRules[::-1]:
+ expression = QtCore.QRegExp(rule[0])
+ index = expression.indexIn(text)
+ while index >= 0:
+ length = expression.matchedLength()
+ self.setFormat(index, length, rule[1])
+ index = expression.indexIn(text, index + length)
+ self.setCurrentBlockState(0)
+
+ # def format_text_color(self):
+ # cursor = self.textCursor()
+ # c_format = cursor.charFormat()
+ # old_color = c_format.foreground()
+ #
+ # for key in self.color_storage:
+ # pass
+
def highlight(self):
hi_selection = QTextEdit.ExtraSelection()
@@ -4272,12 +4514,12 @@ class FCTextAreaLineNumber(QtWidgets.QFrame):
painter.end()
- def __init__(self, *args):
+ def __init__(self, *args, color_dict=None):
QtWidgets.QFrame.__init__(self, *args)
self.setFrameStyle(QtWidgets.QFrame.StyledPanel | QtWidgets.QFrame.Sunken)
- self.edit = self.PlainTextEdit()
+ self.edit = self.PlainTextEdit(color_dict=color_dict)
self.number_bar = self.NumberBar(self.edit)
hbox = QtWidgets.QHBoxLayout(self)
@@ -4683,6 +4925,12 @@ class FlatCAMInfoBar(QtWidgets.QWidget):
layout.addWidget(self.icon)
+ self.red_pmap = QtGui.QPixmap(self.app.resource_location + '/redlight12.png')
+ self.green_pmap = QtGui.QPixmap(self.app.resource_location + '/greenlight12.png')
+ self.yellow_pamap = QtGui.QPixmap(self.app.resource_location + '/yellowlight12.png')
+ self.blue_pamap = QtGui.QPixmap(self.app.resource_location + '/bluelight12.png')
+ self.gray_pmap = QtGui.QPixmap(self.app.resource_location + '/graylight12.png')
+
self.text = QtWidgets.QLabel(self)
self.text.setText(_("Application started ..."))
self.text.setToolTip(_("Hello!"))
@@ -4700,23 +4948,27 @@ class FlatCAMInfoBar(QtWidgets.QWidget):
level = str(level)
if self.lock_pmaps is not True:
- self.pmap.fill()
- if level == "ERROR" or level == "ERROR_NOTCL":
- self.pmap = QtGui.QPixmap(self.app.resource_location + '/redlight12.png')
- elif level.lower() == "success":
- self.pmap = QtGui.QPixmap(self.app.resource_location + '/greenlight12.png')
- elif level == "WARNING" or level == "WARNING_NOTCL":
- self.pmap = QtGui.QPixmap(self.app.resource_location + '/yellowlight12.png')
- elif level.lower() == "selected":
- self.pmap = QtGui.QPixmap(self.app.resource_location + '/bluelight12.png')
- else:
- self.pmap = QtGui.QPixmap(self.app.resource_location + '/graylight12.png')
+ # self.pmap.fill()
+
+ try:
+ if level == "ERROR" or level == "ERROR_NOTCL":
+ self.icon.setPixmap(self.red_pmap)
+ elif level.lower() == "success":
+ self.icon.setPixmap(self.green_pmap)
+ elif level == "WARNING" or level == "WARNING_NOTCL":
+ self.icon.setPixmap(self.yellow_pamap)
+ elif level.lower() == "selected":
+ self.icon.setPixmap(self.blue_pamap)
+ else:
+ self.icon.setPixmap(self.gray_pmap)
+
+ except Exception as e:
+ log.debug("FlatCAMInfoBar.set_status() set Icon --> %s" % str(e))
try:
self.set_text_(text)
- self.icon.setPixmap(self.pmap)
except Exception as e:
- log.debug("FlatCAMInfoBar.set_status() --> %s" % str(e))
+ self.app.log.debug("FlatCAMInfoBar.set_status() set Text --> %s" % str(e))
class FlatCAMSystemTray(QtWidgets.QSystemTrayIcon):
@@ -4806,7 +5058,7 @@ def message_dialog(title, message, kind="info", parent=None):
"error": QtWidgets.QMessageBox.Critical}[str(kind)]
dlg = QtWidgets.QMessageBox(icon, title, message, parent=parent)
dlg.setText(message)
- dlg.exec_()
+ dlg.exec()
def rreplace(s, old, new, occurrence):
diff --git a/appGUI/MainGUI.py b/appGUI/MainGUI.py
index 6fe4e467..569eb3a8 100644
--- a/appGUI/MainGUI.py
+++ b/appGUI/MainGUI.py
@@ -2175,7 +2175,7 @@ class MainGUI(QtWidgets.QMainWindow):
bt_no = msgbox.addButton(_('No'), QtWidgets.QMessageBox.NoRole)
msgbox.setDefaultButton(bt_no)
- msgbox.exec_()
+ msgbox.exec()
response = msgbox.clickedButton()
if forced_clear is True or response == bt_yes:
@@ -3045,7 +3045,7 @@ class MainGUI(QtWidgets.QMainWindow):
messagebox.setStandardButtons(QtWidgets.QMessageBox.Ok)
messagebox.setDefaultButton(QtWidgets.QMessageBox.Ok)
- messagebox.exec_()
+ messagebox.exec()
return
# SHIFT
elif modifiers == QtCore.Qt.ShiftModifier:
@@ -3205,7 +3205,7 @@ class MainGUI(QtWidgets.QMainWindow):
messagebox.setStandardButtons(QtWidgets.QMessageBox.Ok)
messagebox.setDefaultButton(QtWidgets.QMessageBox.Ok)
- messagebox.exec_()
+ messagebox.exec()
# Paint
if key == QtCore.Qt.Key_I or key == 'I':
@@ -3252,7 +3252,7 @@ class MainGUI(QtWidgets.QMainWindow):
messagebox.setStandardButtons(QtWidgets.QMessageBox.Ok)
messagebox.setDefaultButton(QtWidgets.QMessageBox.Ok)
- messagebox.exec_()
+ messagebox.exec()
# Add Text Tool
if key == QtCore.Qt.Key_T or key == 'T':
@@ -3274,7 +3274,7 @@ class MainGUI(QtWidgets.QMainWindow):
messagebox.setStandardButtons(QtWidgets.QMessageBox.Ok)
messagebox.setDefaultButton(QtWidgets.QMessageBox.Ok)
- messagebox.exec_()
+ messagebox.exec()
# Flip on X axis
if key == QtCore.Qt.Key_X or key == 'X':
diff --git a/appGUI/preferences/PreferencesUIManager.py b/appGUI/preferences/PreferencesUIManager.py
index 04eef80c..cb32883b 100644
--- a/appGUI/preferences/PreferencesUIManager.py
+++ b/appGUI/preferences/PreferencesUIManager.py
@@ -953,7 +953,7 @@ class PreferencesUIManager:
msgbox.addButton(_('Cancel'), QtWidgets.QMessageBox.NoRole)
msgbox.setDefaultButton(bt_yes)
- msgbox.exec_()
+ msgbox.exec()
response = msgbox.clickedButton()
if theme_new_val != theme:
@@ -1201,7 +1201,7 @@ class PreferencesUIManager:
msgbox.addButton(_('No'), QtWidgets.QMessageBox.NoRole)
msgbox.setDefaultButton(bt_yes)
- msgbox.exec_()
+ msgbox.exec()
response = msgbox.clickedButton()
if response == bt_yes:
diff --git a/appObjects/FlatCAMScript.py b/appObjects/FlatCAMScript.py
index cd3107f9..b4a5f32e 100644
--- a/appObjects/FlatCAMScript.py
+++ b/appObjects/FlatCAMScript.py
@@ -178,7 +178,7 @@ class ScriptObject(FlatCAMObj):
self.app.shell.open_processing() # Disables input box.
# make sure that the pixmaps are not updated when running this as they will crash
- # TODO find why the pixmaps load crash when run from this object (perhaps another thread?)
+ # TODO find why the pixmaps for the whole app load crash when run from this object (perhaps another thread?)
self.app.ui.fcinfo.lock_pmaps = True
self.script_code = self.script_editor_tab.code_editor.toPlainText()
diff --git a/appTranslation.py b/appTranslation.py
index 61ada23d..9b2a49ad 100644
--- a/appTranslation.py
+++ b/appTranslation.py
@@ -112,7 +112,7 @@ def on_language_apply_click(app, restart=False):
bt_no = msgbox.addButton(_("No"), QtWidgets.QMessageBox.NoRole)
msgbox.setDefaultButton(bt_yes)
- msgbox.exec_()
+ msgbox.exec()
response = msgbox.clickedButton()
if response == bt_no:
@@ -214,7 +214,7 @@ def restart_program(app, ask=None):
msgbox.addButton(_('No'), QtWidgets.QMessageBox.NoRole)
msgbox.setDefaultButton(bt_yes)
- msgbox.exec_()
+ msgbox.exec()
response = msgbox.clickedButton()
if response == bt_yes:
diff --git a/app_Main.py b/app_Main.py
index 969c9726..d7bad8fe 100644
--- a/app_Main.py
+++ b/app_Main.py
@@ -219,6 +219,17 @@ class App(QtCore.QObject):
# File type and filename
file_saved = QtCore.pyqtSignal(str, str)
+ # close app signal
+ close_app_signal = pyqtSignal()
+
+ # will perform the cleanup operation after a Graceful Exit
+ # usefull for the NCC Tool and Paint Tool where some progressive plotting might leave
+ # graphic residues behind
+ cleanup = pyqtSignal()
+
+ # emitted when the new_project is created in a threaded way
+ new_project_signal = pyqtSignal()
+
# Percentage of progress
progress = QtCore.pyqtSignal(int)
@@ -250,14 +261,6 @@ class App(QtCore.QObject):
# signal emitted when jumping
locate_signal = pyqtSignal(tuple, str)
- # close app signal
- close_app_signal = pyqtSignal()
-
- # will perform the cleanup operation after a Graceful Exit
- # usefull for the NCC Tool and Paint Tool where some progressive plotting might leave
- # graphic residues behind
- cleanup = pyqtSignal()
-
proj_selection_changed = pyqtSignal(object, object)
def __init__(self, qapp, user_defaults=True):
@@ -1973,14 +1976,15 @@ class App(QtCore.QObject):
for act in self.ui.menutool.actions():
self.ui.menutool.removeAction(act)
- def init_tools(self):
+ def init_tools(self, init_tcl=True):
"""
Initialize the Tool tab in the notebook side of the central widget.
Remove the actions in the Tools menu.
Instantiate again the FlatCAM tools (plugins).
All this is required when changing the layout: standard, compact etc.
- :return: None
+ :param init_tcl: Bool. If True will init the Tcl Shell
+ :return: None
"""
self.log.debug("init_tools()")
@@ -1992,12 +1996,12 @@ class App(QtCore.QObject):
self.ui.notebook.removeTab(2)
# rebuild the Tools Tab
- self.ui.tool_tab = QtWidgets.QWidget()
- self.ui.tool_tab_layout = QtWidgets.QVBoxLayout(self.ui.tool_tab)
- self.ui.tool_tab_layout.setContentsMargins(2, 2, 2, 2)
- self.ui.notebook.addTab(self.ui.tool_tab, _("Tool"))
- self.ui.tool_scroll_area = VerticalScrollArea()
- self.ui.tool_tab_layout.addWidget(self.ui.tool_scroll_area)
+ # self.ui.tool_tab = QtWidgets.QWidget()
+ # self.ui.tool_tab_layout = QtWidgets.QVBoxLayout(self.ui.tool_tab)
+ # self.ui.tool_tab_layout.setContentsMargins(2, 2, 2, 2)
+ # self.ui.notebook.addTab(self.ui.tool_tab, _("Tool"))
+ # self.ui.tool_scroll_area = VerticalScrollArea()
+ # self.ui.tool_tab_layout.addWidget(self.ui.tool_scroll_area)
# reinstall all the Tools as some may have been removed when the data was removed from the Tools Tab
# first remove all of them
@@ -2010,7 +2014,7 @@ class App(QtCore.QObject):
# third install all of them
try:
- self.install_tools(init_tcl=True)
+ self.install_tools(init_tcl=init_tcl)
except AttributeError:
pass
@@ -2169,7 +2173,7 @@ class App(QtCore.QObject):
self.ui.popmenu_new_geo.triggered.connect(self.app_obj.new_geometry_object)
self.ui.popmenu_new_grb.triggered.connect(self.app_obj.new_gerber_object)
self.ui.popmenu_new_exc.triggered.connect(self.app_obj.new_excellon_object)
- self.ui.popmenu_new_prj.triggered.connect(self.f_handlers.on_file_new)
+ self.ui.popmenu_new_prj.triggered.connect(self.f_handlers.on_file_new_project)
self.ui.zoomfit.triggered.connect(self.on_zoom_fit)
self.ui.clearplot.triggered.connect(self.clear_plots)
@@ -2243,7 +2247,7 @@ class App(QtCore.QObject):
# Toolbar
# File Toolbar Signals
- # ui.file_new_btn.triggered.connect(self.on_file_new)
+ # ui.file_new_btn.triggered.connect(self.on_file_new_project)
self.ui.file_open_btn.triggered.connect(self.f_handlers.on_file_openproject)
self.ui.file_save_btn.triggered.connect(self.f_handlers.on_file_saveproject)
self.ui.file_open_gerber_btn.triggered.connect(self.f_handlers.on_fileopengerber)
@@ -2285,7 +2289,7 @@ class App(QtCore.QObject):
def on_layout(self, index=None, lay=None, connect_signals=True):
"""
- Set the toolbars layout (location)
+ Set the toolbars layout (location).
:param connect_signals: Useful when used in the App.__init__(); bool
:param index:
@@ -2584,7 +2588,8 @@ class App(QtCore.QObject):
"""
Transfers the Geometry or Excellon from it's editor to the current object.
- :return: None
+ :param cleanup: if True then we closed the app when the editor was open so we close first the editor
+ :return: None
"""
self.defaults.report_usage("editor2object()")
@@ -2609,7 +2614,7 @@ class App(QtCore.QObject):
bt_cancel = msgbox.addButton(_('Cancel'), QtWidgets.QMessageBox.RejectRole)
msgbox.setDefaultButton(bt_yes)
- msgbox.exec_()
+ msgbox.exec()
response = msgbox.clickedButton()
if response == bt_yes:
@@ -2843,10 +2848,10 @@ class App(QtCore.QObject):
@QtCore.pyqtSlot(str, bool)
def info(self, msg, shell_echo=True):
"""
- Informs the user. Normally on the status bar, optionally
- also on the shell.
+ Informs the user. Normally on the status bar, optionally also on the shell.
- :param msg: Text to write.
+ :param msg: Text to write. Composed from a first part between brackets which is the level and the rest
+ which is the message. The level part will control the text color and the used icon
:type msg: str
:param shell_echo: Control if to display the message msg in the Shell
:type shell_echo: bool
@@ -2890,13 +2895,28 @@ class App(QtCore.QObject):
self.shell_message(msg)
def info_shell(self, msg, new_line=True):
+ """
+ A handler for a signal that call for printing directly on the Tcl Shell without printing in status bar.
+
+ :param msg: The message to be printed
+ :type msg: str
+ :param new_line: if True then after printing the message add a new line char
+ :type new_line: bool
+ :return: None
+ :rtype: None
+ """
self.shell_message(msg=msg, new_line=new_line)
def save_to_file(self, content_to_save, txt_content):
"""
Save something to a file.
- :return: None
+ :param content_to_save: text when is in HTML
+ :type content_to_save: str
+ :param txt_content: text that is not HTML
+ :type txt_content: str
+ :return: None
+ :rtype: None
"""
self.defaults.report_usage("save_to_file")
self.log.debug("save_to_file()")
@@ -2966,8 +2986,8 @@ class App(QtCore.QObject):
Will register the files opened into record dictionaries. The FlatCAM projects has it's own
dictionary.
- :param kind: type of file that was opened
- :param filename: the path and file name for the file that was opened
+ :param kind: type of file that was opened
+ :param filename: the path and file name for the file that was opened
:return:
"""
self.log.debug("register_recent()")
@@ -3339,7 +3359,7 @@ class App(QtCore.QObject):
closebtn.clicked.connect(self.accept)
- AboutDialog(app=self, parent=self.ui).exec_()
+ AboutDialog(app=self, parent=self.ui).exec()
def on_howto(self):
"""
@@ -3516,14 +3536,14 @@ class App(QtCore.QObject):
# BUTTONS section
closebtn.clicked.connect(self.accept)
- HowtoDialog(app=self, parent=self.ui).exec_()
+ HowtoDialog(app=self, parent=self.ui).exec()
def install_bookmarks(self, book_dict=None):
"""
Install the bookmarks actions in the Help menu -> Bookmarks
- :param book_dict: a dict having the actions text as keys and the weblinks as the values
- :return: None
+ :param book_dict: a dict having the actions text as keys and the weblinks as the values
+ :return: None
"""
if book_dict is None:
@@ -3582,7 +3602,8 @@ class App(QtCore.QObject):
def on_bookmarks_manager(self):
"""
- Adds the bookmark manager in a Tab in Plot Area
+ Adds the bookmark manager in a Tab in Plot Area.
+
:return:
"""
for idx in range(self.ui.plot_tab_area.count()):
@@ -3590,7 +3611,7 @@ class App(QtCore.QObject):
# there can be only one instance of Bookmark Manager at one time
return
- # BookDialog(app=self, storage=self.defaults["global_bookmarks"], parent=self.ui).exec_()
+ # BookDialog(app=self, storage=self.defaults["global_bookmarks"], parent=self.ui).exec()
self.book_dialog_tab = BookmarkManager(app=self, storage=self.defaults["global_bookmarks"], parent=self.ui)
self.book_dialog_tab.setObjectName("bookmarks_tab")
@@ -3609,6 +3630,12 @@ class App(QtCore.QObject):
self.ui.plot_tab_area.setCurrentWidget(self.book_dialog_tab)
def on_backup_site(self):
+ """
+ Called when the user click on the menu entry Help -> Bookmarks -> Backup Site
+
+ :return: None
+ :rtype: None
+ """
msgbox = QtWidgets.QMessageBox()
msgbox.setText(_("This entry will resolve to another website if:\n\n"
"1. FlatCAM.org website is down\n"
@@ -3624,7 +3651,7 @@ class App(QtCore.QObject):
bt_yes = msgbox.addButton(_('Close'), QtWidgets.QMessageBox.YesRole)
msgbox.setDefaultButton(bt_yes)
- msgbox.exec_()
+ msgbox.exec()
# response = msgbox.clickedButton()
def final_save(self):
@@ -3653,7 +3680,7 @@ class App(QtCore.QObject):
bt_cancel = msgbox.addButton(_('Cancel'), QtWidgets.QMessageBox.RejectRole)
msgbox.setDefaultButton(bt_yes)
- msgbox.exec_()
+ msgbox.exec()
response = msgbox.clickedButton()
if response == bt_yes:
@@ -4585,7 +4612,7 @@ class App(QtCore.QObject):
msgbox.addButton(_('Cancel'), QtWidgets.QMessageBox.RejectRole)
msgbox.setDefaultButton(bt_ok)
- msgbox.exec_()
+ msgbox.exec()
response = msgbox.clickedButton()
if response == bt_ok:
@@ -4748,7 +4775,7 @@ class App(QtCore.QObject):
bt_ok = msgbox.addButton(_('Ok'), QtWidgets.QMessageBox.AcceptRole)
msgbox.setDefaultButton(bt_ok)
- msgbox.exec_()
+ msgbox.exec()
# work only if the notebook tab on focus is the Tools_Tab
if notebook_widget_name == 'tool_tab':
@@ -4838,7 +4865,7 @@ class App(QtCore.QObject):
msgbox.addButton(_('Cancel'), QtWidgets.QMessageBox.RejectRole)
msgbox.setDefaultButton(bt_ok)
- msgbox.exec_()
+ msgbox.exec()
response = msgbox.clickedButton()
if self.defaults["global_delete_confirmation"] is False or force_deletion is True:
@@ -5137,7 +5164,7 @@ class App(QtCore.QObject):
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
- if self.exec_() == QtWidgets.QDialog.Accepted:
+ if self.exec() == QtWidgets.QDialog.Accepted:
self.ok = True
self.location_point = self.ref_radio.get_value()
else:
@@ -5401,7 +5428,7 @@ class App(QtCore.QObject):
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
- if self.exec_() == QtWidgets.QDialog.Accepted:
+ if self.exec() == QtWidgets.QDialog.Accepted:
self.ok = True
self.location_point = self.ref_radio.get_value()
else:
@@ -6350,7 +6377,7 @@ class App(QtCore.QObject):
msgbox.addButton(_('No'), QtWidgets.QMessageBox.NoRole)
msgbox.setDefaultButton(bt_yes)
- msgbox.exec_()
+ msgbox.exec()
response = msgbox.clickedButton()
if response == bt_yes:
@@ -7045,10 +7072,12 @@ class App(QtCore.QObject):
def selection_area_handler(self, start_pos, end_pos, sel_type):
"""
- :param start_pos: mouse position when the selection LMB click was done
- :param end_pos: mouse position when the left mouse button is released
- :param sel_type: if True it's a left to right selection (enclosure), if False it's a 'touch' selection
- :return:
+ Called when the mouse selects by dragging left mouse button on canvas.
+
+ :param start_pos: mouse position when the selection LMB click was done
+ :param end_pos: mouse position when the left mouse button is released
+ :param sel_type: if True it's a left to right selection (enclosure), if False it's a 'touch' selection
+ :return: None
"""
poly_selection = Polygon([start_pos, (end_pos[0], start_pos[1]), end_pos, (start_pos[0], end_pos[1])])
@@ -7097,8 +7126,8 @@ class App(QtCore.QObject):
"""
Will select objects clicked on canvas
- :param key: for future use in cumulative selection
- :return:
+ :param key: a keyboard key. for future use in cumulative selection
+ :return: None
"""
# list where we store the overlapped objects under our mouse left click position
@@ -7225,27 +7254,35 @@ class App(QtCore.QObject):
self.log.error("[ERROR] Something went bad in App.select_objects(). %s" % str(e))
def selected_message(self, curr_sel_obj):
+ """
+ Will print a colored message on status bar when the user selects an object on canvas.
+
+ :param curr_sel_obj: Application object that have geometry: Geometry, Gerber, Excellon, CNCJob
+ :type curr_sel_obj:
+ :return: None
+ :rtype: None
+ """
if curr_sel_obj:
if curr_sel_obj.kind == 'gerber':
- self.inform.emit('[selected]{name} {tx}'.format(
+ self.inform.emit('[selected] {name} {tx}'.format(
color='green',
name=str(curr_sel_obj.options['name']),
tx=_("selected"))
)
elif curr_sel_obj.kind == 'excellon':
- self.inform.emit('[selected]{name} {tx}'.format(
+ self.inform.emit('[selected] {name} {tx}'.format(
color='brown',
name=str(curr_sel_obj.options['name']),
tx=_("selected"))
)
elif curr_sel_obj.kind == 'cncjob':
- self.inform.emit('[selected]{name} {tx}'.format(
+ self.inform.emit('[selected] {name} {tx}'.format(
color='blue',
name=str(curr_sel_obj.options['name']),
tx=_("selected"))
)
elif curr_sel_obj.kind == 'geometry':
- self.inform.emit('[selected]{name} {tx}'.format(
+ self.inform.emit('[selected] {name} {tx}'.format(
color='red',
name=str(curr_sel_obj.options['name']),
tx=_("selected"))
@@ -8627,6 +8664,8 @@ class MenuFileHandlers(QtCore.QObject):
self.pagesize = {}
+ self.app.new_project_signal.connect(self.on_new_project_house_keeping)
+
def on_fileopengerber(self, signal, name=None):
"""
File menu callback for opening a Gerber.
@@ -8874,7 +8913,7 @@ class MenuFileHandlers(QtCore.QObject):
msgbox.setInformativeText(msg)
bt_ok = msgbox.addButton(_('Ok'), QtWidgets.QMessageBox.AcceptRole)
msgbox.setDefaultButton(bt_ok)
- msgbox.exec_()
+ msgbox.exec()
return
name = obj.options["name"]
@@ -9222,7 +9261,7 @@ class MenuFileHandlers(QtCore.QObject):
msgbox.setInformativeText(msg)
bt_ok = msgbox.addButton(_('Ok'), QtWidgets.QMessageBox.AcceptRole)
msgbox.setDefaultButton(bt_ok)
- msgbox.exec_()
+ msgbox.exec()
return
@@ -9333,31 +9372,33 @@ class MenuFileHandlers(QtCore.QObject):
bt_cancel = msgbox.addButton(_('Cancel'), QtWidgets.QMessageBox.RejectRole)
msgbox.setDefaultButton(bt_yes)
- msgbox.exec_()
+ msgbox.exec()
response = msgbox.clickedButton()
if response == bt_yes:
- self.on_file_saveprojectas()
+ self.on_file_saveprojectas(threaded=True)
elif response == bt_cancel:
return
elif response == bt_no:
- self.on_file_new()
+ self.on_file_new_project(threaded=True)
else:
- self.on_file_new()
- self.inform.emit('[success] %s...' % _("New Project created"))
+ self.on_file_new_project(threaded=True)
- def on_file_new(self, cli=None):
+ def on_file_new_project(self, cli=None, threaded=None):
"""
Returns the application to its startup state. This method is thread-safe.
- :param cli: Boolean. If True this method was run from command line
- :return: None
+ :param cli: Boolean. If True this method was run from command line
+ :param threaded: Bool. If True some part of the initialization are done threaded
+ :return: None
"""
- self.defaults.report_usage("on_file_new")
+ self.defaults.report_usage("on_file_new_project")
# Remove everything from memory
- self.log.debug("on_file_new()")
+ self.log.debug("on_file_new_project()")
+
+ t0 = time.time()
# close any editor that might be open
if self.app.call_source != 'app':
@@ -9367,9 +9408,6 @@ class MenuFileHandlers(QtCore.QObject):
self.app.exc_editor = AppExcEditor(self.app)
self.app.grb_editor = AppGerberEditor(self.app)
- # Clear pool
- self.app.clear_pool()
-
for obj in self.app.collection.get_list():
# delete shapes left drawn from mark shape_collections, if any
if isinstance(obj, GerberObject):
@@ -9393,9 +9431,6 @@ class MenuFileHandlers(QtCore.QObject):
# delete the exclusion areas
self.app.exc_areas.clear_shapes()
- # tcl needs to be reinitialized, otherwise old shell variables etc remains
- self.app.shell.init_tcl()
-
# delete any selection shape on canvas
self.app.delete_selection_shape()
@@ -9414,8 +9449,17 @@ class MenuFileHandlers(QtCore.QObject):
# Re-fresh project options
self.app.on_options_app2project()
- # Init FlatCAMTools
- self.app.init_tools()
+ if threaded is True:
+ self.app.new_project_signal.emit()
+ else:
+ # Clear pool
+ self.app.clear_pool()
+
+ # Init FlatCAMTools
+ self.app.init_tools(init_tcl=True)
+
+ # tcl needs to be reinitialized, otherwise old shell variables etc remains
+ # self.app.shell.init_tcl()
# Try to close all tabs in the PlotArea but only if the appGUI is active (CLI is None)
if cli is None:
@@ -9427,7 +9471,7 @@ class MenuFileHandlers(QtCore.QObject):
try:
self.app.ui.plot_tab_area.closeTab(index)
except Exception as e:
- self.log.debug("App.on_file_new() --> %s" % str(e))
+ self.log.debug("App.on_file_new_project() --> %s" % str(e))
# # And then add again the Plot Area
self.app.ui.plot_tab_area.insertTab(0, self.app.ui.plot_tab, _("Plot Area"))
@@ -9436,8 +9480,27 @@ class MenuFileHandlers(QtCore.QObject):
# take the focus of the Notebook on Project Tab.
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
+ self.log.debug('%s: %s %s.' % (_("Project created in"), str(time.time() - t0), _("seconds")))
self.app.ui.set_ui_title(name=_("New Project - Not saved"))
+ self.inform.emit('[success] %s...' % _("New Project created"))
+
+ def on_new_project_house_keeping(self):
+ """
+ Do dome of the new project initialization in a threaded way
+
+ :return:
+ :rtype:
+ """
+
+ # Clear pool
+ self.log.debug("New Project: cleaning multiprocessing pool.")
+ self.app.clear_pool()
+
+ # Init FlatCAMTools
+ self.log.debug("New Project: initializing the Tools and Tcl Shell.")
+ self.app.init_tools(init_tcl=True)
+
def on_filenewscript(self, silent=False):
"""
Will create a new script file and open it in the Code Editor
@@ -10862,7 +10925,7 @@ class MenuFileHandlers(QtCore.QObject):
1) Loads and parses file
2) Registers the file as recently opened.
- 3) Calls on_file_new()
+ 3) Calls on_file_new_project()
4) Updates options
5) Calls app_obj.new_object() with the object's from_dict() as init method.
6) Calls plot_all() if plot=True
@@ -10938,7 +11001,7 @@ class MenuFileHandlers(QtCore.QObject):
elif cli is True:
self.app.delete_selection_shape()
else:
- self.on_file_new()
+ self.on_file_new_project()
# Project options
self.app.options.update(d['options'])
diff --git a/assets/examples/cutout_a_gerber.FlatScript b/assets/examples/cutout_a_gerber.FlatScript
index 169ef912..0f439102 100644
--- a/assets/examples/cutout_a_gerber.FlatScript
+++ b/assets/examples/cutout_a_gerber.FlatScript
@@ -3,7 +3,7 @@
# Will cut a PCB piece with a pattern (Gerber file) out of the surrounding PCB material
# #####################################################################################
-puts "**************** RUNNING an EXAMPLE SCRIPT = Cutout a Gerber file *******************"
+puts "\n**************** RUNNING an EXAMPLE SCRIPT = Cutout a Gerber file *******************\n"
# ----------- START: This is needed only for the examples ----------------
# first set the default location where to search for the files to be open and store it to the ROOT_FOLDER variable
diff --git a/assets/examples/isolate_gerber.FlatScript b/assets/examples/isolate_gerber.FlatScript
index d2d0478c..46ada146 100644
--- a/assets/examples/isolate_gerber.FlatScript
+++ b/assets/examples/isolate_gerber.FlatScript
@@ -3,7 +3,7 @@
# Will isolate copper features in a Gerber file by creating surrounding paths around
# #####################################################################################
-puts "**************** RUNNING an EXAMPLE SCRIPT = Isolate a Gerber file *******************"
+puts "\n**************** RUNNING an EXAMPLE SCRIPT = Isolate a Gerber file *******************\n"
# ----------- START: This is needed only for the examples ----------------
# first set the default location where to search for the files to be open and store it to the ROOT_FOLDER variable
diff --git a/assets/examples/open_file.FlatScript b/assets/examples/open_file.FlatScript
index ed84b7ef..3ea84664 100644
--- a/assets/examples/open_file.FlatScript
+++ b/assets/examples/open_file.FlatScript
@@ -3,7 +3,7 @@
# Will open a Gerber (and Excellon) file in FlatCAM
# #####################################################################################
-puts "**************** RUNNING an EXAMPLE SCRIPT = Open a file *******************"
+puts "\n**************** RUNNING an EXAMPLE SCRIPT = Open a file *******************\n"
# ----------- START: This is needed only for the examples ----------------
# first set the default location where to search for the files to be open and store it to the ROOT_FOLDER variable
diff --git a/camlib.py b/camlib.py
index 771261ff..bc161051 100644
--- a/camlib.py
+++ b/camlib.py
@@ -3306,6 +3306,7 @@ class CNCjob(Geometry):
t_gcode += self.doformat(p.toolchange_code, toolchangexy=(temp_locx, temp_locy))
t_gcode += self.doformat(p.z_feedrate_code)
else:
+ t_gcode += self.doformat(p.z_feedrate_code)
t_gcode += self.doformat(p.lift_code)
# Spindle start
diff --git a/tclCommands/TclCommandNew.py b/tclCommands/TclCommandNew.py
index 9a2af1f2..bea2945a 100644
--- a/tclCommands/TclCommandNew.py
+++ b/tclCommands/TclCommandNew.py
@@ -39,4 +39,4 @@ class TclCommandNew(TclCommand):
:return: None or exception
"""
- self.app.on_file_new(cli=True)
+ self.app.on_file_new_project(cli=True)