- changed the name of the new object FlatCAMNotes to a more general one FlatCAMDocument
- changed the way a new FlatCAMScript object is made, the method that is processing the Tcl commands when the Run button is clicked is moved to the FlatCAMObj.FlatCAMScript() class - reused the Multiprocessing Pool declared in the App for the ToolRulesCheck() class - adapted the Project context menu for the new types of FLatCAM objects - modified the setup_recent_files to accommodate the new FlatCAM objects - made sure that when an FlatCAM script object is deleted, it's associated Tab is closed
This commit is contained in:
parent
83f229ed9e
commit
a75bdfb29d
343
FlatCAMApp.py
343
FlatCAMApp.py
|
@ -29,7 +29,7 @@ import gc
|
|||
from xml.dom.minidom import parseString as parse_xml_string
|
||||
|
||||
from multiprocessing.connection import Listener, Client
|
||||
from multiprocessing import Pool
|
||||
from multiprocessing import Pool, cpu_count
|
||||
import socket
|
||||
from array import array
|
||||
|
||||
|
@ -376,7 +376,7 @@ class App(QtCore.QObject):
|
|||
# #############################################################################
|
||||
# ##################### CREATE MULTIPROCESSING POOL ###########################
|
||||
# #############################################################################
|
||||
self.pool = Pool()
|
||||
self.pool = Pool(processes=cpu_count())
|
||||
|
||||
# ##########################################################################
|
||||
# ################## Setting the Splash Screen #############################
|
||||
|
@ -1227,9 +1227,14 @@ class App(QtCore.QObject):
|
|||
'minoffset, multidepth, name, offset, opt_type, order, outname, overlap, '
|
||||
'passes, postamble, pp, ppname_e, ppname_g, preamble, radius, ref, rest, '
|
||||
'rows, shellvar_, scale_factor, spacing_columns, spacing_rows, spindlespeed, '
|
||||
'toolchange_xy, use_threads, value, x, x0, x1, y, y0, y1, z_cut, z_move'
|
||||
,
|
||||
|
||||
'toolchange_xy, use_threads, value, x, x0, x1, y, y0, y1, z_cut, z_move',
|
||||
"script_autocompleter": True,
|
||||
"script_text": "",
|
||||
"script_plot": True,
|
||||
"script_source_file": "",
|
||||
"document_text": "",
|
||||
"document_plot": True,
|
||||
"document_source_file": "",
|
||||
})
|
||||
|
||||
# ############################################################
|
||||
|
@ -1514,9 +1519,11 @@ class App(QtCore.QObject):
|
|||
"tools_panelize_constrainy": 0.0,
|
||||
|
||||
"script_text": "",
|
||||
"script_plot": True,
|
||||
"notes_text": "",
|
||||
"notes_plot": True,
|
||||
"script_plot": False,
|
||||
"script_source_file": "",
|
||||
"document_text": "",
|
||||
"document_plot": False,
|
||||
"document_source_file": "",
|
||||
|
||||
})
|
||||
|
||||
|
@ -3955,7 +3962,7 @@ class App(QtCore.QObject):
|
|||
"cncjob": FlatCAMCNCjob,
|
||||
"geometry": FlatCAMGeometry,
|
||||
"script": FlatCAMScript,
|
||||
"notes": FlatCAMNotes
|
||||
"document": FlatCAMDocument
|
||||
}
|
||||
|
||||
App.log.debug("Calling object constructor...")
|
||||
|
@ -4019,8 +4026,8 @@ class App(QtCore.QObject):
|
|||
self.log.debug("%f seconds converting units." % (t3 - t2))
|
||||
|
||||
# Create the bounding box for the object and then add the results to the obj.options
|
||||
# But not for Scripts or for Notes
|
||||
if kind != 'notes' and kind != 'script':
|
||||
# But not for Scripts or for Documents
|
||||
if kind != 'document' and kind != 'script':
|
||||
try:
|
||||
xmin, ymin, xmax, ymax = obj.bounds()
|
||||
obj.options['xmin'] = xmin
|
||||
|
@ -4031,6 +4038,9 @@ class App(QtCore.QObject):
|
|||
log.warning("The object has no bounds properties. %s" % str(e))
|
||||
return "fail"
|
||||
|
||||
# update the KeyWords list with the name of the file
|
||||
self.myKeywords.append(obj.options['name'])
|
||||
|
||||
FlatCAMApp.App.log.debug("Moving new object back to main thread.")
|
||||
|
||||
# Move the object to the main thread and let the app know that it is available.
|
||||
|
@ -4089,7 +4099,7 @@ class App(QtCore.QObject):
|
|||
|
||||
self.new_object('gerber', 'new_grb', initialize, plot=False)
|
||||
|
||||
def new_script_object(self, name=None):
|
||||
def new_script_object(self, name=None, text=None):
|
||||
"""
|
||||
Creates a new, blank TCL Script object.
|
||||
:param name: a name for the new object
|
||||
|
@ -4097,21 +4107,30 @@ class App(QtCore.QObject):
|
|||
"""
|
||||
self.report_usage("new_script_object()")
|
||||
|
||||
def initialize(obj, self):
|
||||
obj.source_file = _(
|
||||
"#\n"
|
||||
"# CREATE A NEW FLATCAM TCL SCRIPT\n"
|
||||
"# TCL Tutorial here: https://www.tcl.tk/man/tcl8.5/tutorial/tcltutorial.html\n"
|
||||
"#\n\n"
|
||||
"# FlatCAM commands list:\n"
|
||||
"# AddCircle, AddPolygon, AddPolyline, AddRectangle, AlignDrill, AlignDrillGrid, ClearShell, ClearCopper,\n"
|
||||
"# Cncjob, Cutout, Delete, Drillcncjob, ExportGcode, ExportSVG, Exteriors, GeoCutout, GeoUnion, GetNames,\n"
|
||||
"# GetSys, ImportSvg, Interiors, Isolate, Follow, JoinExcellon, JoinGeometry, ListSys, MillDrills,\n"
|
||||
"# MillSlots, Mirror, New, NewGeometry, Offset, OpenExcellon, OpenGCode, OpenGerber, OpenProject,\n"
|
||||
"# Options, Paint, Panelize, Plot, SaveProject, SaveSys, Scale, SetActive, SetSys, Skew, SubtractPoly,\n"
|
||||
"# SubtractRectangle, Version, WriteGCode\n"
|
||||
"#\n\n"
|
||||
if text is not None:
|
||||
new_source_file = text
|
||||
else:
|
||||
new_source_file = _(
|
||||
"#\n"
|
||||
"# CREATE A NEW FLATCAM TCL SCRIPT\n"
|
||||
"# TCL Tutorial here: https://www.tcl.tk/man/tcl8.5/tutorial/tcltutorial.html\n"
|
||||
"#\n\n"
|
||||
"# FlatCAM commands list:\n"
|
||||
"# AddCircle, AddPolygon, AddPolyline, AddRectangle, AlignDrill, AlignDrillGrid, ClearShell, "
|
||||
"ClearCopper,\n"
|
||||
"# Cncjob, Cutout, Delete, Drillcncjob, ExportGcode, ExportSVG, Exteriors, GeoCutout, GeoUnion, "
|
||||
"GetNames,\n"
|
||||
"# GetSys, ImportSvg, Interiors, Isolate, Follow, JoinExcellon, JoinGeometry, ListSys, MillDrills,\n"
|
||||
"# MillSlots, Mirror, New, NewGeometry, Offset, OpenExcellon, OpenGCode, OpenGerber, OpenProject,\n"
|
||||
"# Options, Paint, Panelize, Plot, SaveProject, SaveSys, Scale, SetActive, SetSys, Skew, "
|
||||
"SubtractPoly,\n"
|
||||
"# SubtractRectangle, Version, WriteGCode\n"
|
||||
"#\n\n"
|
||||
)
|
||||
|
||||
def initialize(obj, self):
|
||||
obj.source_file = deepcopy(new_source_file)
|
||||
|
||||
if name is None:
|
||||
outname = 'new_script'
|
||||
else:
|
||||
|
@ -4119,19 +4138,18 @@ class App(QtCore.QObject):
|
|||
|
||||
self.new_object('script', outname, initialize, plot=False)
|
||||
|
||||
|
||||
def new_notes_object(self):
|
||||
def new_document_object(self):
|
||||
"""
|
||||
Creates a new, blank Notes object.
|
||||
Creates a new, blank Document object.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
self.report_usage("new_notes_object()")
|
||||
self.report_usage("new_document_object()")
|
||||
|
||||
def initialize(obj, self):
|
||||
obj.source_file = ""
|
||||
|
||||
self.new_object('notes', 'new_notes', initialize, plot=False)
|
||||
self.new_object('document', 'new_document', initialize, plot=False)
|
||||
|
||||
def on_object_created(self, obj, plot, autoselect):
|
||||
"""
|
||||
|
@ -4169,12 +4187,11 @@ class App(QtCore.QObject):
|
|||
elif obj.kind == 'script':
|
||||
self.inform.emit(_('[selected] {kind} created/selected: <span style="color:{color};">{name}</span>').format(
|
||||
kind=obj.kind.capitalize(), color='orange', name=str(obj.options['name'])))
|
||||
elif obj.kind == 'notes':
|
||||
elif obj.kind == 'document':
|
||||
self.inform.emit(_('[selected] {kind} created/selected: <span style="color:{color};">{name}</span>').format(
|
||||
kind=obj.kind.capitalize(), color='violet', name=str(obj.options['name'])))
|
||||
|
||||
# update the SHELL auto-completer model with the name of the new object
|
||||
self.myKeywords.append(obj.options['name'])
|
||||
self.shell._edit.set_model_data(self.myKeywords)
|
||||
|
||||
if autoselect:
|
||||
|
@ -6971,6 +6988,12 @@ class App(QtCore.QObject):
|
|||
obj_init.slots = deepcopy(obj.slots)
|
||||
obj_init.create_geometry()
|
||||
|
||||
def initialize_script(obj_init, app_obj):
|
||||
obj_init.source_file = deepcopy(obj.source_file)
|
||||
|
||||
def initialize_document(obj_init, app_obj):
|
||||
obj_init.source_file = deepcopy(obj.source_file)
|
||||
|
||||
for obj in self.collection.get_selected():
|
||||
obj_name = obj.options["name"]
|
||||
|
||||
|
@ -6981,6 +7004,10 @@ class App(QtCore.QObject):
|
|||
self.new_object("gerber", str(obj_name) + "_copy", initialize)
|
||||
elif isinstance(obj, FlatCAMGeometry):
|
||||
self.new_object("geometry", str(obj_name) + "_copy", initialize)
|
||||
elif isinstance(obj, FlatCAMScript):
|
||||
self.new_object("script", str(obj_name) + "_copy", initialize_script)
|
||||
elif isinstance(obj, FlatCAMDocument):
|
||||
self.new_object("document", str(obj_name) + "_copy", initialize_document)
|
||||
except Exception as e:
|
||||
return "Operation failed: %s" % str(e)
|
||||
|
||||
|
@ -8376,6 +8403,10 @@ class App(QtCore.QObject):
|
|||
obj.on_exportgcode_button_click()
|
||||
elif type(obj) == FlatCAMGerber:
|
||||
self.on_file_savegerber()
|
||||
elif type(obj) == FlatCAMScript:
|
||||
self.on_file_savescript()
|
||||
elif type(obj) == FlatCAMDocument:
|
||||
self.on_file_savedocument()
|
||||
|
||||
def obj_move(self):
|
||||
self.report_usage("obj_move()")
|
||||
|
@ -8694,6 +8725,94 @@ class App(QtCore.QObject):
|
|||
self.file_opened.emit("Gerber", filename)
|
||||
self.file_saved.emit("Gerber", filename)
|
||||
|
||||
def on_file_savescript(self):
|
||||
"""
|
||||
Callback for menu item in Project context menu.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
self.report_usage("on_file_savescript")
|
||||
App.log.debug("on_file_savescript()")
|
||||
|
||||
obj = self.collection.get_active()
|
||||
if obj is None:
|
||||
self.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("No object selected. Please select an Script object to export."))
|
||||
return
|
||||
|
||||
# Check for more compatible types and add as required
|
||||
if not isinstance(obj, FlatCAMScript):
|
||||
self.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("Failed. Only Script objects can be saved as TCL Script files..."))
|
||||
return
|
||||
|
||||
name = self.collection.get_active().options["name"]
|
||||
|
||||
_filter = "FlatCAM Scripts (*.FlatScript);;All Files (*.*)"
|
||||
try:
|
||||
filename, _f = QtWidgets.QFileDialog.getSaveFileName(
|
||||
caption="Save Script source file",
|
||||
directory=self.get_last_save_folder() + '/' + name,
|
||||
filter=_filter)
|
||||
except TypeError:
|
||||
filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Save Script source file"), filter=_filter)
|
||||
|
||||
filename = str(filename)
|
||||
|
||||
if filename == "":
|
||||
self.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("Save Script source file cancelled."))
|
||||
return
|
||||
else:
|
||||
self.save_source_file(name, filename)
|
||||
if self.defaults["global_open_style"] is False:
|
||||
self.file_opened.emit("Script", filename)
|
||||
self.file_saved.emit("Script", filename)
|
||||
|
||||
def on_file_savedocument(self):
|
||||
"""
|
||||
Callback for menu item in Project context menu.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
self.report_usage("on_file_savedocument")
|
||||
App.log.debug("on_file_savedocument()")
|
||||
|
||||
obj = self.collection.get_active()
|
||||
if obj is None:
|
||||
self.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("No object selected. Please select an Document object to export."))
|
||||
return
|
||||
|
||||
# Check for more compatible types and add as required
|
||||
if not isinstance(obj, FlatCAMScript):
|
||||
self.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("Failed. Only Document objects can be saved as Document files..."))
|
||||
return
|
||||
|
||||
name = self.collection.get_active().options["name"]
|
||||
|
||||
_filter = "FlatCAM Documents (*.FlatDoc);;All Files (*.*)"
|
||||
try:
|
||||
filename, _f = QtWidgets.QFileDialog.getSaveFileName(
|
||||
caption="Save Document source file",
|
||||
directory=self.get_last_save_folder() + '/' + name,
|
||||
filter=_filter)
|
||||
except TypeError:
|
||||
filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Save Document source file"), filter=_filter)
|
||||
|
||||
filename = str(filename)
|
||||
|
||||
if filename == "":
|
||||
self.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("Save Document source file cancelled."))
|
||||
return
|
||||
else:
|
||||
self.save_source_file(name, filename)
|
||||
if self.defaults["global_open_style"] is False:
|
||||
self.file_opened.emit("Document", filename)
|
||||
self.file_saved.emit("Document", filename)
|
||||
|
||||
def on_file_saveexcellon(self):
|
||||
"""
|
||||
Callback for menu item in project context menu.
|
||||
|
@ -9090,65 +9209,22 @@ class App(QtCore.QObject):
|
|||
self.inform.emit('[success] %s' %
|
||||
_("New TCL script file created in Code Editor."))
|
||||
|
||||
flt = "FlatCAM Scripts (*.FlatScript);;All Files (*.*)"
|
||||
|
||||
self.proc_container.view.set_busy(_("Loading..."))
|
||||
|
||||
self.script_editor_tab = TextEditor(app=self)
|
||||
|
||||
# add the tab if it was closed
|
||||
self.ui.plot_tab_area.addTab(self.script_editor_tab, '%s' % _("Script Editor"))
|
||||
self.script_editor_tab.setObjectName('script_editor_tab')
|
||||
|
||||
# delete the absolute and relative position and messages in the infobar
|
||||
self.ui.position_label.setText("")
|
||||
self.ui.rel_position_label.setText("")
|
||||
|
||||
# first clear previous text in text editor (if any)
|
||||
self.script_editor_tab.code_editor.clear()
|
||||
self.script_editor_tab.code_editor.setReadOnly(False)
|
||||
|
||||
self.script_editor_tab.code_editor.completer_enable = True
|
||||
self.script_editor_tab.buttonRun.show()
|
||||
|
||||
# Switch plot_area to CNCJob tab
|
||||
self.ui.plot_tab_area.setCurrentWidget(self.script_editor_tab)
|
||||
|
||||
self.script_editor_tab.buttonOpen.clicked.disconnect()
|
||||
self.script_editor_tab.buttonOpen.clicked.connect(lambda: self.script_editor_tab.handleOpen(filt=flt))
|
||||
self.script_editor_tab.buttonSave.clicked.disconnect()
|
||||
self.script_editor_tab.buttonSave.clicked.connect(lambda: self.script_editor_tab.handleSaveGCode(filt=flt))
|
||||
|
||||
try:
|
||||
self.script_editor_tab.buttonRun.clicked.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
self.script_editor_tab.buttonRun.clicked.connect(self.script_editor_tab.handleRunCode)
|
||||
|
||||
self.script_editor_tab.handleTextChanged()
|
||||
|
||||
if name is not None:
|
||||
self.new_script_object(name=name)
|
||||
script_obj = self.collection.get_by_name(name)
|
||||
self.new_script_object(name=name, text=text)
|
||||
else:
|
||||
self.new_script_object()
|
||||
script_obj = self.collection.get_by_name('new_script')
|
||||
self.new_script_object(text=text)
|
||||
|
||||
script_text = script_obj.source_file
|
||||
|
||||
self.script_editor_tab.t_frame.hide()
|
||||
if text is not None:
|
||||
try:
|
||||
for line in text:
|
||||
self.script_editor_tab.code_editor.append(line)
|
||||
except TypeError:
|
||||
self.script_editor_tab.code_editor.append(text)
|
||||
|
||||
else:
|
||||
self.script_editor_tab.code_editor.append(script_text)
|
||||
self.script_editor_tab.t_frame.show()
|
||||
|
||||
self.proc_container.view.set_idle()
|
||||
# script_text = script_obj.source_file
|
||||
#
|
||||
# self.proc_container.view.set_busy(_("Loading..."))
|
||||
# script_obj.script_editor_tab.t_frame.hide()
|
||||
#
|
||||
# script_obj.script_editor_tab.t_frame.show()
|
||||
# self.proc_container.view.set_idle()
|
||||
|
||||
def on_fileopenscript(self, name=None, silent=False):
|
||||
"""
|
||||
|
@ -9158,53 +9234,29 @@ class App(QtCore.QObject):
|
|||
:param name: name of a Tcl script file to open
|
||||
:return:
|
||||
"""
|
||||
script_content = []
|
||||
|
||||
self.report_usage("on_fileopenscript")
|
||||
App.log.debug("on_fileopenscript()")
|
||||
|
||||
_filter_ = "TCL script (*.FlatScript);;TCL script (*.TCL);;TCL script (*.TXT);;All Files (*.*)"
|
||||
|
||||
if name:
|
||||
filename = name
|
||||
filenames = [name]
|
||||
else:
|
||||
_filter_ = "TCL script (*.FlatScript);;TCL script (*.TCL);;TCL script (*.TXT);;All Files (*.*)"
|
||||
try:
|
||||
filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Open TCL script"),
|
||||
filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Open TCL script"),
|
||||
directory=self.get_last_folder(), filter=_filter_)
|
||||
except TypeError:
|
||||
filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Open TCL script"), filter=_filter_)
|
||||
filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Open TCL script"), filter=_filter_)
|
||||
|
||||
# The Qt methods above will return a QString which can cause problems later.
|
||||
# So far json.dump() will fail to serialize it.
|
||||
# TODO: Improve the serialization methods and remove this fix.
|
||||
filename = str(filename)
|
||||
|
||||
if filename == "":
|
||||
if len(filenames) == 0:
|
||||
if silent is False:
|
||||
self.inform.emit('[WARNING_NOTCL] %s' % _("Open TCL script cancelled."))
|
||||
else:
|
||||
self.proc_container.view.set_busy(_("Loading..."))
|
||||
|
||||
try:
|
||||
with open(filename, "r") as opened_script:
|
||||
try:
|
||||
for line in opened_script:
|
||||
QtWidgets.QApplication.processEvents()
|
||||
proc_line = str(line).strip('\n')
|
||||
script_content.append(proc_line)
|
||||
except Exception as e:
|
||||
log.debug('App.on_fileopenscript() -->%s' % str(e))
|
||||
if silent is False:
|
||||
self.inform.emit('[ERROR] %s %s' %
|
||||
('App.on_fileopenscript() -->', str(e)))
|
||||
return
|
||||
|
||||
if silent is False:
|
||||
self.inform.emit('[success] %s' % _("TCL script file opened in Code Editor."))
|
||||
|
||||
except Exception as e:
|
||||
log.debug("App.on_fileopenscript() -> %s" % str(e))
|
||||
|
||||
self.proc_container.view.set_idle()
|
||||
|
||||
script_name = filename.split('/')[-1].split('\\')[-1]
|
||||
self.on_filenewscript(name=script_name, text=script_content)
|
||||
for filename in filenames:
|
||||
if filename != '':
|
||||
self.worker_task.emit({'fcn': self.open_script, 'params': [filename]})
|
||||
|
||||
def on_filerunscript(self, name=None, silent=False):
|
||||
"""
|
||||
|
@ -10353,8 +10405,6 @@ class App(QtCore.QObject):
|
|||
assert isinstance(app_obj_, App), \
|
||||
"Initializer expected App, got %s" % type(app_obj_)
|
||||
|
||||
self.progress.emit(10)
|
||||
|
||||
try:
|
||||
f = open(filename)
|
||||
gcode = f.read()
|
||||
|
@ -10362,20 +10412,16 @@ class App(QtCore.QObject):
|
|||
except IOError:
|
||||
app_obj_.inform.emit('[ERROR_NOTCL] %s: %s' %
|
||||
(_("Failed to open"), filename))
|
||||
self.progress.emit(0)
|
||||
return "fail"
|
||||
|
||||
job_obj.gcode = gcode
|
||||
|
||||
self.progress.emit(20)
|
||||
|
||||
ret = job_obj.gcode_parse()
|
||||
if ret == "fail":
|
||||
self.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("This is not GCODE"))
|
||||
return "fail"
|
||||
|
||||
self.progress.emit(60)
|
||||
job_obj.create_geometry()
|
||||
|
||||
with self.proc_container.new(_("Opening G-Code.")):
|
||||
|
@ -10398,7 +10444,44 @@ class App(QtCore.QObject):
|
|||
# GUI feedback
|
||||
self.inform.emit('[success] %s: %s' %
|
||||
(_("Opened"), filename))
|
||||
self.progress.emit(100)
|
||||
|
||||
def open_script(self, filename, outname=None, silent=False):
|
||||
"""
|
||||
Opens a Script file, parses it and creates a new object for
|
||||
it in the program. Thread-safe.
|
||||
|
||||
:param outname: Name of the resulting object. None causes the name to be that of the file.
|
||||
:param filename: Script file filename
|
||||
:type filename: str
|
||||
:return: None
|
||||
"""
|
||||
App.log.debug("open_script()")
|
||||
|
||||
with self.proc_container.new(_("Opening TCL Script...")):
|
||||
|
||||
try:
|
||||
with open(filename, "r") as opened_script:
|
||||
script_content = opened_script.readlines()
|
||||
script_content = ''.join(script_content)
|
||||
|
||||
if silent is False:
|
||||
self.inform.emit('[success] %s' % _("TCL script file opened in Code Editor."))
|
||||
except Exception as e:
|
||||
log.debug("App.open_script() -> %s" % str(e))
|
||||
self.inform.emit('[ERROR_NOTCL] %s' % _("Failed to open TCL Script."))
|
||||
return
|
||||
|
||||
# Object name
|
||||
script_name = outname or filename.split('/')[-1].split('\\')[-1]
|
||||
|
||||
# New object creation and file processing
|
||||
self.on_filenewscript(name=script_name, text=script_content)
|
||||
|
||||
# Register recent file
|
||||
self.file_opened.emit("script", filename)
|
||||
|
||||
# GUI feedback
|
||||
self.inform.emit('[success] %s: %s' % (_("Opened"), filename))
|
||||
|
||||
def open_config_file(self, filename, run_from_arg=None):
|
||||
"""
|
||||
|
@ -10816,6 +10899,8 @@ class App(QtCore.QObject):
|
|||
"excellon": "share/drill16.png",
|
||||
'geometry': "share/geometry16.png",
|
||||
"cncjob": "share/cnc16.png",
|
||||
"script": "share/script_new24.png",
|
||||
"document": "share/notes16_1.png",
|
||||
"project": "share/project16.png",
|
||||
"svg": "share/geometry16.png",
|
||||
"dxf": "share/dxf16.png",
|
||||
|
@ -10829,6 +10914,8 @@ class App(QtCore.QObject):
|
|||
'excellon': lambda fname: self.worker_task.emit({'fcn': self.open_excellon, 'params': [fname]}),
|
||||
'geometry': lambda fname: self.worker_task.emit({'fcn': self.import_dxf, 'params': [fname]}),
|
||||
'cncjob': lambda fname: self.worker_task.emit({'fcn': self.open_gcode, 'params': [fname]}),
|
||||
"script": lambda fname: self.worker_task.emit({'fcn': self.open_script, 'params': [fname]}),
|
||||
"document": None,
|
||||
'project': self.open_project,
|
||||
'svg': self.import_svg,
|
||||
'dxf': self.import_dxf,
|
||||
|
|
170
FlatCAMObj.py
170
FlatCAMObj.py
|
@ -16,7 +16,10 @@ from flatcamGUI.ObjectUI import *
|
|||
from FlatCAMCommon import LoudDict
|
||||
from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
|
||||
from camlib import *
|
||||
|
||||
import itertools
|
||||
import tkinter as tk
|
||||
import sys
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
|
@ -164,11 +167,23 @@ class FlatCAMObj(QtCore.QObject):
|
|||
|
||||
assert isinstance(self.ui, ObjectUI)
|
||||
self.ui.name_entry.returnPressed.connect(self.on_name_activate)
|
||||
self.ui.offset_button.clicked.connect(self.on_offset_button_click)
|
||||
self.ui.scale_button.clicked.connect(self.on_scale_button_click)
|
||||
|
||||
self.ui.offsetvector_entry.returnPressed.connect(self.on_offset_button_click)
|
||||
self.ui.scale_entry.returnPressed.connect(self.on_scale_button_click)
|
||||
try:
|
||||
# it will raise an exception for those FlatCAM objects that do not build UI with the common elements
|
||||
self.ui.offset_button.clicked.connect(self.on_offset_button_click)
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
try:
|
||||
self.ui.scale_button.clicked.connect(self.on_scale_button_click)
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
try:
|
||||
self.ui.offsetvector_entry.returnPressed.connect(self.on_offset_button_click)
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
try:
|
||||
self.ui.scale_entry.returnPressed.connect(self.on_scale_button_click)
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
# self.ui.skew_button.clicked.connect(self.on_skew_button_click)
|
||||
|
||||
def build_ui(self):
|
||||
|
@ -6481,6 +6496,9 @@ class FlatCAMScript(FlatCAMObj):
|
|||
FlatCAMObj.set_ui(self, ui)
|
||||
FlatCAMApp.App.log.debug("FlatCAMScript.set_ui()")
|
||||
|
||||
assert isinstance(self.ui, ScriptObjectUI), \
|
||||
"Expected a ScriptObjectUI, got %s" % type(self.ui)
|
||||
|
||||
self.units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
|
||||
|
||||
if self.units == "IN":
|
||||
|
@ -6488,26 +6506,137 @@ class FlatCAMScript(FlatCAMObj):
|
|||
else:
|
||||
self.decimals = 2
|
||||
|
||||
# Fill form fields only on object create
|
||||
self.to_form()
|
||||
|
||||
# Show/Hide Advanced Options
|
||||
if self.app.defaults["global_app_level"] == 'b':
|
||||
self.ui.level.setText(_(
|
||||
'<span style="color:green;"><b>Basic</b></span>'
|
||||
))
|
||||
else:
|
||||
self.ui.level.setText(_(
|
||||
'<span style="color:red;"><b>Advanced</b></span>'
|
||||
))
|
||||
|
||||
self.script_editor_tab = TextEditor(app=self.app)
|
||||
|
||||
# first clear previous text in text editor (if any)
|
||||
self.script_editor_tab.code_editor.clear()
|
||||
self.script_editor_tab.code_editor.setReadOnly(False)
|
||||
|
||||
self.script_editor_tab.buttonRun.show()
|
||||
|
||||
self.ui.autocomplete_cb.set_value(self.app.defaults['script_autocompleter'])
|
||||
self.on_autocomplete_changed(state= self.app.defaults['script_autocompleter'])
|
||||
|
||||
flt = "FlatCAM Scripts (*.FlatScript);;All Files (*.*)"
|
||||
self.script_editor_tab.buttonOpen.clicked.disconnect()
|
||||
self.script_editor_tab.buttonOpen.clicked.connect(lambda: self.script_editor_tab.handleOpen(filt=flt))
|
||||
self.script_editor_tab.buttonSave.clicked.disconnect()
|
||||
self.script_editor_tab.buttonSave.clicked.connect(lambda: self.script_editor_tab.handleSaveGCode(filt=flt))
|
||||
|
||||
self.script_editor_tab.buttonRun.clicked.connect(self.handle_run_code)
|
||||
|
||||
self.script_editor_tab.handleTextChanged()
|
||||
|
||||
self.ui.autocomplete_cb.stateChanged.connect(self.on_autocomplete_changed)
|
||||
|
||||
# add the source file to the Code Editor
|
||||
for line in self.source_file.splitlines():
|
||||
self.script_editor_tab.code_editor.append(line)
|
||||
|
||||
self.build_ui()
|
||||
|
||||
def build_ui(self):
|
||||
pass
|
||||
FlatCAMObj.build_ui(self)
|
||||
tab_here = False
|
||||
|
||||
# try to not add too many times a tab that it is already installed
|
||||
for idx in range(self.app.ui.plot_tab_area.count()):
|
||||
if self.app.ui.plot_tab_area.widget(idx).objectName() == self.options['name']:
|
||||
tab_here = True
|
||||
break
|
||||
|
||||
# add the tab if it is not already added
|
||||
if tab_here is False:
|
||||
self.app.ui.plot_tab_area.addTab(self.script_editor_tab, '%s' % _("Script Editor"))
|
||||
self.script_editor_tab.setObjectName(self.options['name'])
|
||||
|
||||
# Switch plot_area to CNCJob tab
|
||||
self.app.ui.plot_tab_area.setCurrentWidget(self.script_editor_tab)
|
||||
|
||||
def handle_run_code(self):
|
||||
# trying to run a Tcl command without having the Shell open will create some warnings because the Tcl Shell
|
||||
# tries to print on a hidden widget, therefore show the dock if hidden
|
||||
if self.app.ui.shell_dock.isHidden():
|
||||
self.app.ui.shell_dock.show()
|
||||
|
||||
self.script_code = deepcopy(self.script_editor_tab.code_editor.toPlainText())
|
||||
|
||||
old_line = ''
|
||||
for tcl_command_line in self.script_code.splitlines():
|
||||
# do not process lines starting with '#' = comment and empty lines
|
||||
if not tcl_command_line.startswith('#') and tcl_command_line != '':
|
||||
# id FlatCAM is run in Windows then replace all the slashes with
|
||||
# the UNIX style slash that TCL understands
|
||||
if sys.platform == 'win32':
|
||||
if "open" in tcl_command_line:
|
||||
tcl_command_line = tcl_command_line.replace('\\', '/')
|
||||
|
||||
if old_line != '':
|
||||
new_command = old_line + tcl_command_line + '\n'
|
||||
else:
|
||||
new_command = tcl_command_line
|
||||
|
||||
# execute the actual Tcl command
|
||||
try:
|
||||
self.app.shell.open_proccessing() # Disables input box.
|
||||
|
||||
result = self.app.tcl.eval(str(new_command))
|
||||
if result != 'None':
|
||||
self.app.shell.append_output(result + '\n')
|
||||
|
||||
old_line = ''
|
||||
except tk.TclError:
|
||||
old_line = old_line + tcl_command_line + '\n'
|
||||
except Exception as e:
|
||||
log.debug("App.handleRunCode() --> %s" % str(e))
|
||||
|
||||
if old_line != '':
|
||||
# it means that the script finished with an error
|
||||
result = self.app.tcl.eval("set errorInfo")
|
||||
log.error("Exec command Exception: %s" % (result + '\n'))
|
||||
self.app.shell.append_error('ERROR: ' + result + '\n')
|
||||
|
||||
self.app.shell.close_proccessing()
|
||||
|
||||
def on_autocomplete_changed(self, state):
|
||||
if state:
|
||||
self.script_editor_tab.code_editor.completer_enable = True
|
||||
else:
|
||||
self.script_editor_tab.code_editor.completer_enable = False
|
||||
|
||||
|
||||
class FlatCAMNotes(FlatCAMObj):
|
||||
class FlatCAMDocument(FlatCAMObj):
|
||||
"""
|
||||
Represents a Notes object.
|
||||
Represents a Document object.
|
||||
"""
|
||||
optionChanged = QtCore.pyqtSignal(str)
|
||||
ui_type = NotesObjectUI
|
||||
ui_type = DocumentObjectUI
|
||||
|
||||
def __init__(self, name):
|
||||
FlatCAMApp.App.log.debug("Creating a Notes object...")
|
||||
FlatCAMApp.App.log.debug("Creating a Document object...")
|
||||
FlatCAMObj.__init__(self, name)
|
||||
|
||||
self.kind = "notes"
|
||||
self.kind = "document"
|
||||
|
||||
def set_ui(self, ui):
|
||||
FlatCAMObj.set_ui(self, ui)
|
||||
FlatCAMApp.App.log.debug("FlatCAMNotes.set_ui()")
|
||||
FlatCAMApp.App.log.debug("FlatCAMDocument.set_ui()")
|
||||
|
||||
assert isinstance(self.ui, DocumentObjectUI), \
|
||||
"Expected a DocumentObjectUI, got %s" % type(self.ui)
|
||||
|
||||
self.units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
|
||||
|
||||
|
@ -6516,7 +6645,22 @@ class FlatCAMNotes(FlatCAMObj):
|
|||
else:
|
||||
self.decimals = 2
|
||||
|
||||
# Fill form fields only on object create
|
||||
self.to_form()
|
||||
|
||||
# Show/Hide Advanced Options
|
||||
if self.app.defaults["global_app_level"] == 'b':
|
||||
self.ui.level.setText(_(
|
||||
'<span style="color:green;"><b>Basic</b></span>'
|
||||
))
|
||||
else:
|
||||
self.ui.level.setText(_(
|
||||
'<span style="color:red;"><b>Advanced</b></span>'
|
||||
))
|
||||
|
||||
self.build_ui()
|
||||
|
||||
def build_ui(self):
|
||||
pass
|
||||
FlatCAMObj.build_ui(self)
|
||||
|
||||
# end of file
|
||||
|
|
|
@ -188,7 +188,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
|
|||
("geometry", "Geometry"),
|
||||
("cncjob", "CNC Job"),
|
||||
("script", "Scripts"),
|
||||
("notes", "Notes"),
|
||||
("document", "Document"),
|
||||
]
|
||||
|
||||
classdict = {
|
||||
|
@ -197,7 +197,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
|
|||
"cncjob": FlatCAMCNCjob,
|
||||
"geometry": FlatCAMGeometry,
|
||||
"script": FlatCAMScript,
|
||||
"notes": FlatCAMNotes
|
||||
"document": FlatCAMDocument
|
||||
}
|
||||
|
||||
icon_files = {
|
||||
|
@ -206,7 +206,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
|
|||
"cncjob": "share/cnc16.png",
|
||||
"geometry": "share/geometry16.png",
|
||||
"script": "share/script_new16.png",
|
||||
"notes": "share/notes16_1.png"
|
||||
"document": "share/notes16_1.png"
|
||||
}
|
||||
|
||||
root_item = None
|
||||
|
@ -328,6 +328,14 @@ class ObjectCollection(QtCore.QAbstractItemModel):
|
|||
self.app.ui.menuprojectedit.setVisible(False)
|
||||
if type(obj) != FlatCAMGerber and type(obj) != FlatCAMExcellon and type(obj) != FlatCAMCNCjob:
|
||||
self.app.ui.menuprojectviewsource.setVisible(False)
|
||||
if type(obj) != FlatCAMGerber and type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon and \
|
||||
type(obj) != FlatCAMCNCjob:
|
||||
# meaning for Scripts and for Document type of FlatCAM object
|
||||
self.app.ui.menuprojectenable.setVisible(False)
|
||||
self.app.ui.menuprojectdisable.setVisible(False)
|
||||
self.app.ui.menuprojectedit.setVisible(False)
|
||||
self.app.ui.menuprojectproperties.setVisible(False)
|
||||
self.app.ui.menuprojectgeneratecnc.setVisible(False)
|
||||
else:
|
||||
self.app.ui.menuprojectgeneratecnc.setVisible(False)
|
||||
|
||||
|
@ -576,12 +584,19 @@ class ObjectCollection(QtCore.QAbstractItemModel):
|
|||
# send signal with the object that is deleted
|
||||
# self.app.object_status_changed.emit(active.obj, 'delete')
|
||||
|
||||
# some objects add a Tab on creation, close it here
|
||||
for idx in range(self.app.ui.plot_tab_area.count()):
|
||||
if self.app.ui.plot_tab_area.widget(idx).objectName() == active.obj.options['name']:
|
||||
self.app.ui.plot_tab_area.removeTab(idx)
|
||||
break
|
||||
|
||||
# update the SHELL auto-completer model data
|
||||
name = active.obj.options['name']
|
||||
try:
|
||||
self.app.myKeywords.remove(name)
|
||||
self.app.shell._edit.set_model_data(self.app.myKeywords)
|
||||
self.app.ui.code_editor.set_model_data(self.app.myKeywords)
|
||||
# this is not needed any more because now the code editor is created on demand
|
||||
# self.app.ui.code_editor.set_model_data(self.app.myKeywords)
|
||||
except Exception as e:
|
||||
log.debug(
|
||||
"delete_active() --> Could not remove the old object name from auto-completer model list. %s" % str(e))
|
||||
|
@ -742,7 +757,12 @@ class ObjectCollection(QtCore.QAbstractItemModel):
|
|||
elif obj.kind == 'geometry':
|
||||
self.app.inform.emit(_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
||||
color='red', name=str(obj.options['name'])))
|
||||
|
||||
elif obj.kind == 'script':
|
||||
self.app.inform.emit(_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
||||
color='orange', name=str(obj.options['name'])))
|
||||
elif obj.kind == 'document':
|
||||
self.app.inform.emit(_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
||||
color='violet', name=str(obj.options['name'])))
|
||||
except IndexError:
|
||||
# FlatCAMApp.App.log.debug("on_list_selection_change(): Index Error (Nothing selected?)")
|
||||
self.app.inform.emit('')
|
||||
|
|
|
@ -15,6 +15,12 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- fixed bug in Geometry Editor that did not allow the copy of geometric elements
|
||||
- created a new class that holds all the Code Editor functionality and integrated as a Editor in FlatCAM, the location is in flatcamEditors folder
|
||||
- remade all the functions for view_source, scripts and view_code to use the new TextEditor class; now all the Code Editor tabs are being kept alive, before only one could be in an open state
|
||||
- changed the name of the new object FlatCAMNotes to a more general one FlatCAMDocument
|
||||
- changed the way a new FlatCAMScript object is made, the method that is processing the Tcl commands when the Run button is clicked is moved to the FlatCAMObj.FlatCAMScript() class
|
||||
- reused the Multiprocessing Pool declared in the App for the ToolRulesCheck() class
|
||||
- adapted the Project context menu for the new types of FLatCAM objects
|
||||
- modified the setup_recent_files to accommodate the new FlatCAM objects
|
||||
- made sure that when an FlatCAM script object is deleted, it's associated Tab is closed
|
||||
|
||||
1.10.2019
|
||||
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
from flatcamGUI.GUIElements import *
|
||||
from PyQt5 import QtPrintSupport
|
||||
|
||||
import tkinter as tk
|
||||
from copy import deepcopy
|
||||
|
||||
import sys
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -39,10 +34,10 @@ class TextEditor(QtWidgets.QWidget):
|
|||
|
||||
self.code_editor = FCTextAreaExtended()
|
||||
stylesheet = """
|
||||
QTextEdit { selection-background-color:yellow;
|
||||
selection-color:black;
|
||||
}
|
||||
"""
|
||||
QTextEdit { selection-background-color:yellow;
|
||||
selection-color:black;
|
||||
}
|
||||
"""
|
||||
|
||||
self.code_editor.setStyleSheet(stylesheet)
|
||||
|
||||
|
@ -129,7 +124,6 @@ class TextEditor(QtWidgets.QWidget):
|
|||
self.code_editor.set_model_data(self.app.myKeywords)
|
||||
|
||||
self.gcode_edited = ''
|
||||
self.script_code = ''
|
||||
|
||||
def handlePrint(self):
|
||||
self.app.report_usage("handlePrint()")
|
||||
|
@ -269,79 +263,38 @@ class TextEditor(QtWidgets.QWidget):
|
|||
self.app.clipboard.setText(text)
|
||||
self.app.inform.emit(_("Code Editor content copied to clipboard ..."))
|
||||
|
||||
def handleRunCode(self):
|
||||
# trying to run a Tcl command without having the Shell open will create some warnings because the Tcl Shell
|
||||
# tries to print on a hidden widget, therefore show the dock if hidden
|
||||
if self.app.ui.shell_dock.isHidden():
|
||||
self.app.ui.shell_dock.show()
|
||||
|
||||
self.script_code = deepcopy(self.code_editor.toPlainText())
|
||||
|
||||
old_line = ''
|
||||
for tcl_command_line in self.app.script_code.splitlines():
|
||||
# do not process lines starting with '#' = comment and empty lines
|
||||
if not tcl_command_line.startswith('#') and tcl_command_line != '':
|
||||
# id FlatCAM is run in Windows then replace all the slashes with
|
||||
# the UNIX style slash that TCL understands
|
||||
if sys.platform == 'win32':
|
||||
if "open" in tcl_command_line:
|
||||
tcl_command_line = tcl_command_line.replace('\\', '/')
|
||||
|
||||
if old_line != '':
|
||||
new_command = old_line + tcl_command_line + '\n'
|
||||
else:
|
||||
new_command = tcl_command_line
|
||||
|
||||
# execute the actual Tcl command
|
||||
try:
|
||||
self.app.shell.open_proccessing() # Disables input box.
|
||||
|
||||
result = self.app.tcl.eval(str(new_command))
|
||||
if result != 'None':
|
||||
self.app.shell.append_output(result + '\n')
|
||||
|
||||
old_line = ''
|
||||
except tk.TclError:
|
||||
old_line = old_line + tcl_command_line + '\n'
|
||||
except Exception as e:
|
||||
log.debug("App.handleRunCode() --> %s" % str(e))
|
||||
|
||||
if old_line != '':
|
||||
# it means that the script finished with an error
|
||||
result = self.app.tcl.eval("set errorInfo")
|
||||
log.error("Exec command Exception: %s" % (result + '\n'))
|
||||
self.app.shell.append_error('ERROR: ' + result + '\n')
|
||||
|
||||
self.app.shell.close_proccessing()
|
||||
|
||||
def closeEvent(self, QCloseEvent):
|
||||
try:
|
||||
self.code_editor.textChanged.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.buttonOpen.clicked.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.buttonPrint.clicked.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.buttonPreview.clicked.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.buttonFind.clicked.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.buttonReplace.clicked.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.button_copy_all.clicked.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
super().closeEvent(QCloseEvent)
|
||||
# def closeEvent(self, QCloseEvent):
|
||||
# try:
|
||||
# self.code_editor.textChanged.disconnect()
|
||||
# except TypeError:
|
||||
# pass
|
||||
# try:
|
||||
# self.buttonOpen.clicked.disconnect()
|
||||
# except TypeError:
|
||||
# pass
|
||||
# try:
|
||||
# self.buttonPrint.clicked.disconnect()
|
||||
# except TypeError:
|
||||
# pass
|
||||
# try:
|
||||
# self.buttonPreview.clicked.disconnect()
|
||||
# except TypeError:
|
||||
# pass
|
||||
# try:
|
||||
# self.buttonFind.clicked.disconnect()
|
||||
# except TypeError:
|
||||
# pass
|
||||
# try:
|
||||
# self.buttonReplace.clicked.disconnect()
|
||||
# except TypeError:
|
||||
# pass
|
||||
# try:
|
||||
# self.button_copy_all.clicked.disconnect()
|
||||
# except TypeError:
|
||||
# pass
|
||||
# try:
|
||||
# self.buttonRun.clicked.disconnect()
|
||||
# except TypeError:
|
||||
# pass
|
||||
#
|
||||
# super().closeEvent(QCloseEvent)
|
||||
|
|
|
@ -30,7 +30,7 @@ class ObjectUI(QtWidgets.QWidget):
|
|||
put UI elements in ObjectUI.custom_box (QtWidgets.QLayout).
|
||||
"""
|
||||
|
||||
def __init__(self, icon_file='share/flatcam_icon32.png', title=_('FlatCAM Object'), parent=None):
|
||||
def __init__(self, icon_file='share/flatcam_icon32.png', title=_('FlatCAM Object'), parent=None, common=True):
|
||||
QtWidgets.QWidget.__init__(self, parent=parent)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
|
@ -74,62 +74,62 @@ class ObjectUI(QtWidgets.QWidget):
|
|||
# ###########################
|
||||
# ## Common to all objects ##
|
||||
# ###########################
|
||||
if common is True:
|
||||
# ### Scale ####
|
||||
self.scale_label = QtWidgets.QLabel('<b>%s:</b>' % _('Scale'))
|
||||
self.scale_label.setToolTip(
|
||||
_("Change the size of the object.")
|
||||
)
|
||||
layout.addWidget(self.scale_label)
|
||||
|
||||
# ### Scale ####
|
||||
self.scale_label = QtWidgets.QLabel('<b>%s:</b>' % _('Scale'))
|
||||
self.scale_label.setToolTip(
|
||||
_("Change the size of the object.")
|
||||
)
|
||||
layout.addWidget(self.scale_label)
|
||||
self.scale_grid = QtWidgets.QGridLayout()
|
||||
layout.addLayout(self.scale_grid)
|
||||
|
||||
self.scale_grid = QtWidgets.QGridLayout()
|
||||
layout.addLayout(self.scale_grid)
|
||||
# Factor
|
||||
faclabel = QtWidgets.QLabel('%s:' % _('Factor'))
|
||||
faclabel.setToolTip(
|
||||
_("Factor by which to multiply\n"
|
||||
"geometric features of this object.")
|
||||
)
|
||||
self.scale_grid.addWidget(faclabel, 0, 0)
|
||||
self.scale_entry = FloatEntry2()
|
||||
self.scale_entry.set_value(1.0)
|
||||
self.scale_grid.addWidget(self.scale_entry, 0, 1)
|
||||
|
||||
# Factor
|
||||
faclabel = QtWidgets.QLabel('%s:' % _('Factor'))
|
||||
faclabel.setToolTip(
|
||||
_("Factor by which to multiply\n"
|
||||
"geometric features of this object.")
|
||||
)
|
||||
self.scale_grid.addWidget(faclabel, 0, 0)
|
||||
self.scale_entry = FloatEntry2()
|
||||
self.scale_entry.set_value(1.0)
|
||||
self.scale_grid.addWidget(self.scale_entry, 0, 1)
|
||||
# GO Button
|
||||
self.scale_button = QtWidgets.QPushButton(_('Scale'))
|
||||
self.scale_button.setToolTip(
|
||||
_("Perform scaling operation.")
|
||||
)
|
||||
self.scale_button.setMinimumWidth(70)
|
||||
self.scale_grid.addWidget(self.scale_button, 0, 2)
|
||||
|
||||
# GO Button
|
||||
self.scale_button = QtWidgets.QPushButton(_('Scale'))
|
||||
self.scale_button.setToolTip(
|
||||
_("Perform scaling operation.")
|
||||
)
|
||||
self.scale_button.setMinimumWidth(70)
|
||||
self.scale_grid.addWidget(self.scale_button, 0, 2)
|
||||
# ### Offset ####
|
||||
self.offset_label = QtWidgets.QLabel('<b>%s:</b>' % _('Offset'))
|
||||
self.offset_label.setToolTip(
|
||||
_("Change the position of this object.")
|
||||
)
|
||||
layout.addWidget(self.offset_label)
|
||||
|
||||
# ### Offset ####
|
||||
self.offset_label = QtWidgets.QLabel('<b>%s:</b>' % _('Offset'))
|
||||
self.offset_label.setToolTip(
|
||||
_("Change the position of this object.")
|
||||
)
|
||||
layout.addWidget(self.offset_label)
|
||||
self.offset_grid = QtWidgets.QGridLayout()
|
||||
layout.addLayout(self.offset_grid)
|
||||
|
||||
self.offset_grid = QtWidgets.QGridLayout()
|
||||
layout.addLayout(self.offset_grid)
|
||||
self.offset_vectorlabel = QtWidgets.QLabel('%s:' % _('Vector'))
|
||||
self.offset_vectorlabel.setToolTip(
|
||||
_("Amount by which to move the object\n"
|
||||
"in the x and y axes in (x, y) format.")
|
||||
)
|
||||
self.offset_grid.addWidget(self.offset_vectorlabel, 0, 0)
|
||||
self.offsetvector_entry = EvalEntry2()
|
||||
self.offsetvector_entry.setText("(0.0, 0.0)")
|
||||
self.offset_grid.addWidget(self.offsetvector_entry, 0, 1)
|
||||
|
||||
self.offset_vectorlabel = QtWidgets.QLabel('%s:' % _('Vector'))
|
||||
self.offset_vectorlabel.setToolTip(
|
||||
_("Amount by which to move the object\n"
|
||||
"in the x and y axes in (x, y) format.")
|
||||
)
|
||||
self.offset_grid.addWidget(self.offset_vectorlabel, 0, 0)
|
||||
self.offsetvector_entry = EvalEntry2()
|
||||
self.offsetvector_entry.setText("(0.0, 0.0)")
|
||||
self.offset_grid.addWidget(self.offsetvector_entry, 0, 1)
|
||||
|
||||
self.offset_button = QtWidgets.QPushButton(_('Offset'))
|
||||
self.offset_button.setToolTip(
|
||||
_("Perform the offset operation.")
|
||||
)
|
||||
self.offset_button.setMinimumWidth(70)
|
||||
self.offset_grid.addWidget(self.offset_button, 0, 2)
|
||||
self.offset_button = QtWidgets.QPushButton(_('Offset'))
|
||||
self.offset_button.setToolTip(
|
||||
_("Perform the offset operation.")
|
||||
)
|
||||
self.offset_button.setMinimumWidth(70)
|
||||
self.offset_grid.addWidget(self.offset_button, 0, 2)
|
||||
|
||||
layout.addStretch()
|
||||
|
||||
|
@ -1726,286 +1726,48 @@ class ScriptObjectUI(ObjectUI):
|
|||
be placed in ``self.custom_box`` to preserve the layout.
|
||||
"""
|
||||
|
||||
ObjectUI.__init__(self, title=_('Script Object'), icon_file='share/cnc32.png', parent=parent)
|
||||
|
||||
# Scale and offset ans skew are not available for CNCJob objects.
|
||||
# Hiding from the GUI.
|
||||
for i in range(0, self.scale_grid.count()):
|
||||
self.scale_grid.itemAt(i).widget().hide()
|
||||
self.scale_label.hide()
|
||||
self.scale_button.hide()
|
||||
|
||||
for i in range(0, self.offset_grid.count()):
|
||||
self.offset_grid.itemAt(i).widget().hide()
|
||||
self.offset_label.hide()
|
||||
self.offset_button.hide()
|
||||
|
||||
# ## Plot options
|
||||
self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
|
||||
self.custom_box.addWidget(self.plot_options_label)
|
||||
|
||||
self.cncplot_method_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot kind"))
|
||||
self.cncplot_method_label.setToolTip(
|
||||
_(
|
||||
"This selects the kind of geometries on the canvas to plot.\n"
|
||||
"Those can be either of type 'Travel' which means the moves\n"
|
||||
"above the work piece or it can be of type 'Cut',\n"
|
||||
"which means the moves that cut into the material."
|
||||
)
|
||||
)
|
||||
|
||||
self.cncplot_method_combo = RadioSet([
|
||||
{"label": _("All"), "value": "all"},
|
||||
{"label": _("Travel"), "value": "travel"},
|
||||
{"label": _("Cut"), "value": "cut"}
|
||||
], stretch=False)
|
||||
|
||||
self.annotation_label = QtWidgets.QLabel("<b>%s:</b>" % _("Display Annotation"))
|
||||
self.annotation_label.setToolTip(
|
||||
_("This selects if to display text annotation on the plot.\n"
|
||||
"When checked it will display numbers in order for each end\n"
|
||||
"of a travel line.")
|
||||
)
|
||||
self.annotation_cb = FCCheckBox()
|
||||
ObjectUI.__init__(self, title=_('Script Object'),
|
||||
icon_file='share/script_new24.png',
|
||||
parent=parent,
|
||||
common=False)
|
||||
|
||||
# ## Object name
|
||||
self.name_hlay = QtWidgets.QHBoxLayout()
|
||||
self.custom_box.addLayout(self.name_hlay)
|
||||
|
||||
name_label = QtWidgets.QLabel("<b>%s:</b>" % _("Name"))
|
||||
self.name_entry = FCEntry()
|
||||
self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
self.name_hlay.addWidget(name_label)
|
||||
self.name_hlay.addWidget(self.name_entry)
|
||||
|
||||
self.t_distance_label = QtWidgets.QLabel("<b>%s:</b>" % _("Travelled dist."))
|
||||
self.t_distance_label.setToolTip(
|
||||
_("This is the total travelled distance on X-Y plane.\n"
|
||||
"In current units.")
|
||||
)
|
||||
self.t_distance_entry = FCEntry()
|
||||
self.t_distance_entry.setToolTip(
|
||||
_("This is the total travelled distance on X-Y plane.\n"
|
||||
"In current units.")
|
||||
)
|
||||
self.units_label = QtWidgets.QLabel()
|
||||
|
||||
self.t_time_label = QtWidgets.QLabel("<b>%s:</b>" % _("Estimated time"))
|
||||
self.t_time_label.setToolTip(
|
||||
_("This is the estimated time to do the routing/drilling,\n"
|
||||
"without the time spent in ToolChange events.")
|
||||
)
|
||||
self.t_time_entry = FCEntry()
|
||||
self.t_time_entry.setToolTip(
|
||||
_("This is the estimated time to do the routing/drilling,\n"
|
||||
"without the time spent in ToolChange events.")
|
||||
)
|
||||
self.units_time_label = QtWidgets.QLabel()
|
||||
|
||||
f_lay = QtWidgets.QGridLayout()
|
||||
f_lay.setColumnStretch(1, 1)
|
||||
f_lay.setColumnStretch(2, 1)
|
||||
|
||||
self.custom_box.addLayout(f_lay)
|
||||
f_lay.addWidget(self.cncplot_method_label, 0, 0)
|
||||
f_lay.addWidget(self.cncplot_method_combo, 0, 1)
|
||||
f_lay.addWidget(QtWidgets.QLabel(''), 0, 2)
|
||||
f_lay.addWidget(self.annotation_label, 1, 0)
|
||||
f_lay.addWidget(self.annotation_cb, 1, 1)
|
||||
f_lay.addWidget(QtWidgets.QLabel(''), 1, 2)
|
||||
f_lay.addWidget(self.t_distance_label, 2, 0)
|
||||
f_lay.addWidget(self.t_distance_entry, 2, 1)
|
||||
f_lay.addWidget(self.units_label, 2, 2)
|
||||
f_lay.addWidget(self.t_time_label, 3, 0)
|
||||
f_lay.addWidget(self.t_time_entry, 3, 1)
|
||||
f_lay.addWidget(self.units_time_label, 3, 2)
|
||||
|
||||
self.t_distance_label.hide()
|
||||
self.t_distance_entry.setVisible(False)
|
||||
self.t_time_label.hide()
|
||||
self.t_time_entry.setVisible(False)
|
||||
|
||||
e1_lbl = QtWidgets.QLabel('')
|
||||
self.custom_box.addWidget(e1_lbl)
|
||||
|
||||
hlay = QtWidgets.QHBoxLayout()
|
||||
self.custom_box.addLayout(hlay)
|
||||
|
||||
# CNC Tools Table for plot
|
||||
self.cnc_tools_table_label = QtWidgets.QLabel('<b>%s</b>' % _('CNC Tools Table'))
|
||||
self.cnc_tools_table_label.setToolTip(
|
||||
_(
|
||||
"Tools in this CNCJob object used for cutting.\n"
|
||||
"The tool diameter is used for plotting on canvas.\n"
|
||||
"The 'Offset' entry will set an offset for the cut.\n"
|
||||
"'Offset' can be inside, outside, on path (none) and custom.\n"
|
||||
"'Type' entry is only informative and it allow to know the \n"
|
||||
"intent of using the current tool. \n"
|
||||
"It can be Rough(ing), Finish(ing) or Iso(lation).\n"
|
||||
"The 'Tool type'(TT) can be circular with 1 to 4 teeths(C1..C4),\n"
|
||||
"ball(B), or V-Shaped(V)."
|
||||
)
|
||||
)
|
||||
hlay.addWidget(self.cnc_tools_table_label)
|
||||
|
||||
# Plot CB
|
||||
# self.plot_cb = QtWidgets.QCheckBox('Plot')
|
||||
self.plot_cb = FCCheckBox(_('Plot Object'))
|
||||
self.plot_cb.setToolTip(
|
||||
_("Plot (show) this object.")
|
||||
)
|
||||
self.plot_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
hlay.addStretch()
|
||||
hlay.addWidget(self.plot_cb)
|
||||
|
||||
self.cnc_tools_table = FCTable()
|
||||
self.custom_box.addWidget(self.cnc_tools_table)
|
||||
|
||||
# self.cnc_tools_table.setColumnCount(4)
|
||||
# self.cnc_tools_table.setHorizontalHeaderLabels(['#', 'Dia', 'Plot', ''])
|
||||
# self.cnc_tools_table.setColumnHidden(3, True)
|
||||
self.cnc_tools_table.setColumnCount(7)
|
||||
self.cnc_tools_table.setColumnWidth(0, 20)
|
||||
self.cnc_tools_table.setHorizontalHeaderLabels(['#', _('Dia'), _('Offset'), _('Type'), _('TT'), '',
|
||||
_('P')])
|
||||
self.cnc_tools_table.setColumnHidden(5, True)
|
||||
# stylesheet = "::section{Background-color:rgb(239,239,245)}"
|
||||
# self.cnc_tools_table.horizontalHeader().setStyleSheet(stylesheet)
|
||||
|
||||
# Update plot button
|
||||
self.updateplot_button = QtWidgets.QPushButton(_('Update Plot'))
|
||||
self.updateplot_button.setToolTip(
|
||||
_("Update the plot.")
|
||||
)
|
||||
self.custom_box.addWidget(self.updateplot_button)
|
||||
|
||||
# ####################
|
||||
# ## Export G-Code ##
|
||||
# ####################
|
||||
self.export_gcode_label = QtWidgets.QLabel("<b>%s:</b>" % _("Export CNC Code"))
|
||||
self.export_gcode_label.setToolTip(
|
||||
_("Export and save G-Code to\n"
|
||||
"make this object to a file.")
|
||||
)
|
||||
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.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.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 postprocessor 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.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(
|
||||
_("Opens TAB to view/modify/print G-Code\n"
|
||||
"file.")
|
||||
self.autocomplete_cb = FCCheckBox("%s" % _("Auto Completer"))
|
||||
self.autocomplete_cb.setToolTip(
|
||||
_("This selects if the auto completer is enabled in the Script Editor.")
|
||||
)
|
||||
|
||||
# GO Button
|
||||
self.export_gcode_button = QtWidgets.QPushButton(_('Save CNC Code'))
|
||||
self.export_gcode_button.setToolTip(
|
||||
_("Opens dialog to save G-Code\n"
|
||||
"file.")
|
||||
self.autocomplete_cb.setStyleSheet(
|
||||
"""
|
||||
QCheckBox {font-weight: bold; color: black}
|
||||
"""
|
||||
)
|
||||
h_lay.addWidget(self.autocomplete_cb)
|
||||
h_lay.addStretch()
|
||||
|
||||
h_lay.addWidget(self.modify_gcode_button)
|
||||
h_lay.addWidget(self.export_gcode_button)
|
||||
# self.custom_box.addWidget(self.export_gcode_button)
|
||||
# Plot CB - this is added only for compatibility; other FlatCAM objects expect it and the mechanism is already
|
||||
# established and I don't want to changed it right now
|
||||
self.plot_cb = FCCheckBox()
|
||||
self.plot_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
self.custom_box.addWidget(self.plot_cb)
|
||||
self.plot_cb.hide()
|
||||
|
||||
class NotesObjectUI(ObjectUI):
|
||||
self.custom_box.addStretch()
|
||||
|
||||
|
||||
class DocumentObjectUI(ObjectUI):
|
||||
"""
|
||||
User interface for Notes objects.
|
||||
"""
|
||||
|
@ -2016,283 +1778,28 @@ class NotesObjectUI(ObjectUI):
|
|||
be placed in ``self.custom_box`` to preserve the layout.
|
||||
"""
|
||||
|
||||
ObjectUI.__init__(self, title=_('Notes Object'), icon_file='share/cnc32.png', parent=parent)
|
||||
|
||||
# Scale and offset ans skew are not available for CNCJob objects.
|
||||
# Hiding from the GUI.
|
||||
for i in range(0, self.scale_grid.count()):
|
||||
self.scale_grid.itemAt(i).widget().hide()
|
||||
self.scale_label.hide()
|
||||
self.scale_button.hide()
|
||||
|
||||
for i in range(0, self.offset_grid.count()):
|
||||
self.offset_grid.itemAt(i).widget().hide()
|
||||
self.offset_label.hide()
|
||||
self.offset_button.hide()
|
||||
|
||||
# ## Plot options
|
||||
self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
|
||||
self.custom_box.addWidget(self.plot_options_label)
|
||||
|
||||
self.cncplot_method_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot kind"))
|
||||
self.cncplot_method_label.setToolTip(
|
||||
_(
|
||||
"This selects the kind of geometries on the canvas to plot.\n"
|
||||
"Those can be either of type 'Travel' which means the moves\n"
|
||||
"above the work piece or it can be of type 'Cut',\n"
|
||||
"which means the moves that cut into the material."
|
||||
)
|
||||
)
|
||||
|
||||
self.cncplot_method_combo = RadioSet([
|
||||
{"label": _("All"), "value": "all"},
|
||||
{"label": _("Travel"), "value": "travel"},
|
||||
{"label": _("Cut"), "value": "cut"}
|
||||
], stretch=False)
|
||||
|
||||
self.annotation_label = QtWidgets.QLabel("<b>%s:</b>" % _("Display Annotation"))
|
||||
self.annotation_label.setToolTip(
|
||||
_("This selects if to display text annotation on the plot.\n"
|
||||
"When checked it will display numbers in order for each end\n"
|
||||
"of a travel line.")
|
||||
)
|
||||
self.annotation_cb = FCCheckBox()
|
||||
ObjectUI.__init__(self, title=_('Document Object'),
|
||||
icon_file='share/notes16_1.png',
|
||||
parent=parent,
|
||||
common=False)
|
||||
|
||||
# ## Object name
|
||||
self.name_hlay = QtWidgets.QHBoxLayout()
|
||||
self.custom_box.addLayout(self.name_hlay)
|
||||
|
||||
name_label = QtWidgets.QLabel("<b>%s:</b>" % _("Name"))
|
||||
self.name_entry = FCEntry()
|
||||
self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
self.name_hlay.addWidget(name_label)
|
||||
self.name_hlay.addWidget(self.name_entry)
|
||||
|
||||
self.t_distance_label = QtWidgets.QLabel("<b>%s:</b>" % _("Travelled dist."))
|
||||
self.t_distance_label.setToolTip(
|
||||
_("This is the total travelled distance on X-Y plane.\n"
|
||||
"In current units.")
|
||||
)
|
||||
self.t_distance_entry = FCEntry()
|
||||
self.t_distance_entry.setToolTip(
|
||||
_("This is the total travelled distance on X-Y plane.\n"
|
||||
"In current units.")
|
||||
)
|
||||
self.units_label = QtWidgets.QLabel()
|
||||
|
||||
self.t_time_label = QtWidgets.QLabel("<b>%s:</b>" % _("Estimated time"))
|
||||
self.t_time_label.setToolTip(
|
||||
_("This is the estimated time to do the routing/drilling,\n"
|
||||
"without the time spent in ToolChange events.")
|
||||
)
|
||||
self.t_time_entry = FCEntry()
|
||||
self.t_time_entry.setToolTip(
|
||||
_("This is the estimated time to do the routing/drilling,\n"
|
||||
"without the time spent in ToolChange events.")
|
||||
)
|
||||
self.units_time_label = QtWidgets.QLabel()
|
||||
|
||||
f_lay = QtWidgets.QGridLayout()
|
||||
f_lay.setColumnStretch(1, 1)
|
||||
f_lay.setColumnStretch(2, 1)
|
||||
|
||||
self.custom_box.addLayout(f_lay)
|
||||
f_lay.addWidget(self.cncplot_method_label, 0, 0)
|
||||
f_lay.addWidget(self.cncplot_method_combo, 0, 1)
|
||||
f_lay.addWidget(QtWidgets.QLabel(''), 0, 2)
|
||||
f_lay.addWidget(self.annotation_label, 1, 0)
|
||||
f_lay.addWidget(self.annotation_cb, 1, 1)
|
||||
f_lay.addWidget(QtWidgets.QLabel(''), 1, 2)
|
||||
f_lay.addWidget(self.t_distance_label, 2, 0)
|
||||
f_lay.addWidget(self.t_distance_entry, 2, 1)
|
||||
f_lay.addWidget(self.units_label, 2, 2)
|
||||
f_lay.addWidget(self.t_time_label, 3, 0)
|
||||
f_lay.addWidget(self.t_time_entry, 3, 1)
|
||||
f_lay.addWidget(self.units_time_label, 3, 2)
|
||||
|
||||
self.t_distance_label.hide()
|
||||
self.t_distance_entry.setVisible(False)
|
||||
self.t_time_label.hide()
|
||||
self.t_time_entry.setVisible(False)
|
||||
|
||||
e1_lbl = QtWidgets.QLabel('')
|
||||
self.custom_box.addWidget(e1_lbl)
|
||||
|
||||
hlay = QtWidgets.QHBoxLayout()
|
||||
self.custom_box.addLayout(hlay)
|
||||
|
||||
# CNC Tools Table for plot
|
||||
self.cnc_tools_table_label = QtWidgets.QLabel('<b>%s</b>' % _('CNC Tools Table'))
|
||||
self.cnc_tools_table_label.setToolTip(
|
||||
_(
|
||||
"Tools in this CNCJob object used for cutting.\n"
|
||||
"The tool diameter is used for plotting on canvas.\n"
|
||||
"The 'Offset' entry will set an offset for the cut.\n"
|
||||
"'Offset' can be inside, outside, on path (none) and custom.\n"
|
||||
"'Type' entry is only informative and it allow to know the \n"
|
||||
"intent of using the current tool. \n"
|
||||
"It can be Rough(ing), Finish(ing) or Iso(lation).\n"
|
||||
"The 'Tool type'(TT) can be circular with 1 to 4 teeths(C1..C4),\n"
|
||||
"ball(B), or V-Shaped(V)."
|
||||
)
|
||||
)
|
||||
hlay.addWidget(self.cnc_tools_table_label)
|
||||
|
||||
# Plot CB
|
||||
# self.plot_cb = QtWidgets.QCheckBox('Plot')
|
||||
self.plot_cb = FCCheckBox(_('Plot Object'))
|
||||
self.plot_cb.setToolTip(
|
||||
_("Plot (show) this object.")
|
||||
)
|
||||
# Plot CB - this is added only for compatibility; other FlatCAM objects expect it and the mechanism is already
|
||||
# established and I don't want to changed it right now
|
||||
self.plot_cb = FCCheckBox()
|
||||
self.plot_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
hlay.addStretch()
|
||||
hlay.addWidget(self.plot_cb)
|
||||
self.custom_box.addWidget(self.plot_cb)
|
||||
self.plot_cb.hide()
|
||||
|
||||
self.cnc_tools_table = FCTable()
|
||||
self.custom_box.addWidget(self.cnc_tools_table)
|
||||
|
||||
# self.cnc_tools_table.setColumnCount(4)
|
||||
# self.cnc_tools_table.setHorizontalHeaderLabels(['#', 'Dia', 'Plot', ''])
|
||||
# self.cnc_tools_table.setColumnHidden(3, True)
|
||||
self.cnc_tools_table.setColumnCount(7)
|
||||
self.cnc_tools_table.setColumnWidth(0, 20)
|
||||
self.cnc_tools_table.setHorizontalHeaderLabels(['#', _('Dia'), _('Offset'), _('Type'), _('TT'), '',
|
||||
_('P')])
|
||||
self.cnc_tools_table.setColumnHidden(5, True)
|
||||
# stylesheet = "::section{Background-color:rgb(239,239,245)}"
|
||||
# self.cnc_tools_table.horizontalHeader().setStyleSheet(stylesheet)
|
||||
|
||||
# Update plot button
|
||||
self.updateplot_button = QtWidgets.QPushButton(_('Update Plot'))
|
||||
self.updateplot_button.setToolTip(
|
||||
_("Update the plot.")
|
||||
)
|
||||
self.custom_box.addWidget(self.updateplot_button)
|
||||
|
||||
# ####################
|
||||
# ## Export G-Code ##
|
||||
# ####################
|
||||
self.export_gcode_label = QtWidgets.QLabel("<b>%s:</b>" % _("Export CNC Code"))
|
||||
self.export_gcode_label.setToolTip(
|
||||
_("Export and save G-Code to\n"
|
||||
"make this object to a file.")
|
||||
)
|
||||
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.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.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 postprocessor 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.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(
|
||||
_("Opens TAB to view/modify/print G-Code\n"
|
||||
"file.")
|
||||
)
|
||||
|
||||
# GO Button
|
||||
self.export_gcode_button = QtWidgets.QPushButton(_('Save CNC Code'))
|
||||
self.export_gcode_button.setToolTip(
|
||||
_("Opens dialog to save G-Code\n"
|
||||
"file.")
|
||||
)
|
||||
|
||||
h_lay.addWidget(self.modify_gcode_button)
|
||||
h_lay.addWidget(self.export_gcode_button)
|
||||
# self.custom_box.addWidget(self.export_gcode_button)
|
||||
self.custom_box.addStretch()
|
||||
|
||||
# end of file
|
||||
|
|
|
@ -486,7 +486,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.constrain_flag = False
|
||||
|
||||
# Multiprocessing Process Pool
|
||||
self.pool = Pool(processes=cpu_count())
|
||||
self.pool = self.app.pool
|
||||
self.results = None
|
||||
|
||||
# def on_object_loaded(self, index, row):
|
||||
|
|
|
@ -47,7 +47,7 @@ class TclCommandCncjob(TclCommandSignaled):
|
|||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['name']
|
||||
required = []
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
|
@ -88,16 +88,24 @@ class TclCommandCncjob(TclCommandSignaled):
|
|||
:return: None or exception
|
||||
"""
|
||||
|
||||
name = args['name']
|
||||
|
||||
if 'outname' not in args:
|
||||
args['outname'] = str(name) + "_cnc"
|
||||
name = ''
|
||||
|
||||
if 'muted' in args:
|
||||
muted = args['muted']
|
||||
else:
|
||||
muted = 0
|
||||
|
||||
try:
|
||||
name = args['name']
|
||||
except KeyError:
|
||||
if muted == 0:
|
||||
self.raise_tcl_error("Object name is missing")
|
||||
else:
|
||||
return "fail"
|
||||
|
||||
if 'outname' not in args:
|
||||
args['outname'] = str(name) + "_cnc"
|
||||
|
||||
obj = self.app.collection.get_by_name(str(name), isCaseSensitive=False)
|
||||
|
||||
if obj is None:
|
||||
|
|
Loading…
Reference in New Issue