From 05ae92726c3cf87c3575fa7fef7c666c173a9e51 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Wed, 6 Feb 2019 16:59:17 +0200 Subject: [PATCH] - renamed the theme to layout because it is really a layout change - combined the geocutout and cutout_any TCL commands - work in progress --- FlatCAMApp.py | 16 +-- FlatCAMEditor.py | 16 +-- FlatCAMGUI.py | 39 ++++--- README.md | 2 + tclCommands/TclCommandCutoutAny.py | 179 ----------------------------- tclCommands/TclCommandGeoCutout.py | 178 +++++++++++++++++++--------- tclCommands/__init__.py | 1 - 7 files changed, 159 insertions(+), 272 deletions(-) delete mode 100644 tclCommands/TclCommandCutoutAny.py diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 408b23f6..7cdd099f 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -1212,7 +1212,7 @@ class App(QtCore.QObject): self.general_defaults_form.general_gui_group.wk_cb.currentIndexChanged.connect(self.on_workspace_modified) self.general_defaults_form.general_gui_group.workspace_cb.stateChanged.connect(self.on_workspace) - self.general_defaults_form.general_gui_group.theme_combo.activated.connect(self.on_theme) + self.general_defaults_form.general_gui_group.layout_combo.activated.connect(self.on_layout) # Modify G-CODE Plot Area TAB self.ui.code_editor.textChanged.connect(self.handleTextChanged) @@ -1257,7 +1257,7 @@ class App(QtCore.QObject): # Auto-complete KEYWORDS self.tcl_commands_list = ['add_circle', 'add_poly', 'add_polygon', 'add_polyline', 'add_rectangle', 'aligndrill', 'clear', - 'aligndrillgrid', 'cncjob', 'cutout', 'cutout_any', 'delete', 'drillcncjob', + 'aligndrillgrid', 'cncjob', 'cutout', 'delete', 'drillcncjob', 'export_gcode', 'export_svg', 'ext', 'exteriors', 'follow', 'geo_union', 'geocutout', 'get_names', 'get_sys', 'getsys', 'help', 'import_svg', 'interiors', 'isolate', 'join_excellon', @@ -3245,13 +3245,13 @@ class App(QtCore.QObject): self.general_defaults_form.general_gui_group.workspace_cb.setChecked(True) self.on_workspace() - def on_theme(self): - self.report_usage("on_theme()") + def on_layout(self): + self.report_usage("on_layout()") - current_theme= self.general_defaults_form.general_gui_group.theme_combo.get_value().lower() + current_layout= self.general_defaults_form.general_gui_group.layout_combo.get_value().lower() settings = QSettings("Open Source", "FlatCAM") - settings.setValue('theme', current_theme) + settings.setValue('layout', current_layout) # This will write the setting to the platform specific storage. del settings @@ -3265,7 +3265,7 @@ class App(QtCore.QObject): self.ui.removeToolBar(self.ui.geo_edit_toolbar) self.ui.removeToolBar(self.ui.snap_toolbar) - if current_theme == 'standard': + if current_layout == 'standard': ### TOOLBAR INSTALLATION ### self.ui.toolbarfile = QtWidgets.QToolBar('File Toolbar') self.ui.toolbarfile.setObjectName('File_TB') @@ -3300,7 +3300,7 @@ class App(QtCore.QObject): self.ui.corner_snap_btn.setVisible(False) self.ui.snap_magnet.setVisible(False) - elif current_theme == 'compact': + elif current_layout == 'compact': ### TOOLBAR INSTALLATION ### self.ui.toolbarfile = QtWidgets.QToolBar('File Toolbar') self.ui.toolbarfile.setObjectName('File_TB') diff --git a/FlatCAMEditor.py b/FlatCAMEditor.py index 84cb50d7..a8fe3591 100644 --- a/FlatCAMEditor.py +++ b/FlatCAMEditor.py @@ -2083,16 +2083,16 @@ class FlatCAMGeoEditor(QtCore.QObject): self.app.ui.geo_edit_toolbar.setDisabled(True) settings = QSettings("Open Source", "FlatCAM") - if settings.contains("theme"): - theme = settings.value('theme', type=str) - if theme == 'standard': + if settings.contains("layout"): + layout = settings.value('layout', type=str) + if layout == 'standard': # self.app.ui.geo_edit_toolbar.setVisible(False) self.app.ui.snap_max_dist_entry.setEnabled(False) self.app.ui.corner_snap_btn.setEnabled(False) self.app.ui.snap_magnet.setVisible(False) self.app.ui.corner_snap_btn.setVisible(False) - elif theme == 'compact': + elif layout == 'compact': # self.app.ui.geo_edit_toolbar.setVisible(True) self.app.ui.snap_max_dist_entry.setEnabled(False) @@ -4224,16 +4224,16 @@ class FlatCAMExcEditor(QtCore.QObject): self.app.ui.exc_edit_toolbar.setDisabled(True) settings = QSettings("Open Source", "FlatCAM") - if settings.contains("theme"): - theme = settings.value('theme', type=str) - if theme == 'standard': + if settings.contains("layout"): + layout = settings.value('layout', type=str) + if layout == 'standard': # self.app.ui.exc_edit_toolbar.setVisible(False) self.app.ui.snap_max_dist_entry.setEnabled(False) self.app.ui.corner_snap_btn.setEnabled(False) self.app.ui.snap_magnet.setVisible(False) self.app.ui.corner_snap_btn.setVisible(False) - elif theme == 'compact': + elif layout == 'compact': # self.app.ui.exc_edit_toolbar.setVisible(True) self.app.ui.snap_max_dist_entry.setEnabled(False) diff --git a/FlatCAMGUI.py b/FlatCAMGUI.py index beb885ea..e1e30c9e 100644 --- a/FlatCAMGUI.py +++ b/FlatCAMGUI.py @@ -435,11 +435,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.snap_toolbar.setObjectName('Snap_TB') settings = QSettings("Open Source", "FlatCAM") - if settings.contains("theme"): - theme = settings.value('theme', type=str) - if theme == 'standard': + if settings.contains("layout"): + layout = settings.value('layout', type=str) + if layout == 'standard': self.addToolBar(self.snap_toolbar) - elif theme == 'compact': + elif layout == 'compact': self.snap_toolbar.setMaximumHeight(30) self.splitter_left.addWidget(self.snap_toolbar) else: @@ -1336,9 +1336,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.restoreState(saved_gui_state) log.debug("FlatCAMGUI.__init__() --> UI state restored.") - if settings.contains("theme"): - theme = settings.value('theme', type=str) - if theme == 'standard': + if settings.contains("layout"): + layout = settings.value('layout', type=str) + if layout == 'standard': self.exc_edit_toolbar.setVisible(False) self.exc_edit_toolbar.setDisabled(True) self.geo_edit_toolbar.setVisible(False) @@ -1346,7 +1346,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.corner_snap_btn.setVisible(False) self.snap_magnet.setVisible(False) - elif theme == 'compact': + elif layout == 'compact': self.exc_edit_toolbar.setDisabled(True) self.geo_edit_toolbar.setDisabled(True) self.snap_magnet.setVisible(True) @@ -1477,9 +1477,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.grid_snap_btn.trigger() settings = QSettings("Open Source", "FlatCAM") - if settings.contains("theme"): - theme = settings.value('theme', type=str) - if theme == 'standard': + if settings.contains("layout"): + layout = settings.value('layout', type=str) + if layout == 'standard': self.exc_edit_toolbar.setVisible(False) self.exc_edit_toolbar.setDisabled(True) self.geo_edit_toolbar.setVisible(False) @@ -1487,7 +1487,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow): self.corner_snap_btn.setVisible(False) self.snap_magnet.setVisible(False) - elif theme == 'compact': + elif layout == 'compact': self.exc_edit_toolbar.setVisible(True) self.exc_edit_toolbar.setDisabled(True) self.geo_edit_toolbar.setVisible(True) @@ -2219,14 +2219,15 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI): self.form_box_child_11.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) # Theme selection - self.theme_label = QtWidgets.QLabel('Theme:') + self.layout_label = QtWidgets.QLabel('Layout:') self.alt_sf_color_label.setToolTip( - "Select a theme for FlatCAM." + "Select an layout for FlatCAM." ) - self.theme_combo = FCComboBox() - self.theme_combo.addItem("Standard") - self.theme_combo.addItem("Compact") - self.theme_combo.setCurrentIndex(0) + self.layout_combo = FCComboBox() + self.layout_combo.addItem("Choose ...") + self.layout_combo.addItem("Standard") + self.layout_combo.addItem("Compact") + self.layout_combo.setCurrentIndex(0) # Just to add empty rows self.spacelabel = QtWidgets.QLabel('') @@ -2255,7 +2256,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI): self.form_box.addRow(self.sel_draw_color_label, self.form_box_child_11) self.form_box.addRow(self.spacelabel, self.spacelabel) - self.form_box.addRow(self.theme_label, self.theme_combo) + self.form_box.addRow(self.layout_label, self.layout_combo) # Add the QFormLayout that holds the Application general defaults # to the main layout of this TAB self.layout.addLayout(self.form_box) diff --git a/README.md b/README.md index 7941afd3..aba4d043 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ CAD program, and create G-Code for Isolation routing. - fixed FlatCAM crash when trying to make drills GCode out of a file that have only slots. - changed the messages for Units Conversion - all key shortcuts work across the entire application; moved all the shortcuts definitions in FlatCAMGUI.keyPressEvent() +- renamed the theme to layout because it is really a layout change +- combined the geocutout and cutout_any TCL commands - work in progress 5.02.3019 diff --git a/tclCommands/TclCommandCutoutAny.py b/tclCommands/TclCommandCutoutAny.py deleted file mode 100644 index 49fd718c..00000000 --- a/tclCommands/TclCommandCutoutAny.py +++ /dev/null @@ -1,179 +0,0 @@ -from ObjectCollection import * -from tclCommands.TclCommand import TclCommand - - -class TclCommandCutoutAny(TclCommand): - """ - Tcl shell command to create a board cutout geometry. Allow cutout for any shape. - - example: - - """ - - # List of all command aliases, to be able use old - # names for backward compatibility (add_poly, add_polygon) - aliases = ['cutout_any', 'cut_any'] - - # Dictionary of types from Tcl command, needs to be ordered - arg_names = collections.OrderedDict([ - ('name', str), - ]) - - # Dictionary of types from Tcl command, needs to be ordered, - # this is for options like -optionname value - option_types = collections.OrderedDict([ - ('dia', float), - ('margin', float), - ('gapsize', float), - ('gaps', str) - ]) - - # array of mandatory options for current Tcl command: required = {'name','outname'} - required = ['name'] - - # structured help for current command, args needs to be ordered - help = { - 'main': 'Creates board cutout from an object (Gerber or Geometry) of any shape', - 'args': collections.OrderedDict([ - ('name', 'Name of the object.'), - ('dia', 'Tool diameter.'), - ('margin', 'Margin over bounds.'), - ('gapsize', 'size of gap.'), - ('gaps', "type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right, '2tb' = 2top-2bottom, " - "'2lr' = 2left-2right, '4' = 4 cuts, '8' = 8 cuts") - ]), - 'examples': [] - } - - def execute(self, args, unnamed_args): - """ - - :param args: - :param unnamed_args: - :return: - """ - - def subtract_rectangle(obj_, x0, y0, x1, y1): - pts = [(x0, y0), (x1, y0), (x1, y1), (x0, y1)] - obj_.subtract_polygon(pts) - - if 'name' in args: - name = args['name'] - else: - self.app.inform.emit( - "[WARNING]The name of the object for which cutout is done is missing. Add it and retry.") - return - - if 'margin' in args: - margin = args['margin'] - else: - margin = 0.001 - - if 'dia' in args: - dia = args['dia'] - else: - dia = 0.1 - - if 'gaps' in args: - gaps = args['gaps'] - else: - gaps = 4 - - if 'gapsize' in args: - gapsize = args['gapsize'] - else: - gapsize = 0.1 - - # Get source object. - try: - cutout_obj = self.app.collection.get_by_name(str(name)) - except: - return "Could not retrieve object: %s" % name - - if 0 in {dia}: - self.app.inform.emit("[WARNING]Tool Diameter is zero value. Change it to a positive integer.") - return "Tool Diameter is zero value. Change it to a positive integer." - - if gaps not in ['lr', 'tb', '2lr', '2tb', 4, 8]: - self.app.inform.emit("[WARNING]Gaps value can be only one of: 'lr', 'tb', '2lr', '2tb', 4 or 8. " - "Fill in a correct value and retry. ") - return - - # Get min and max data for each object as we just cut rectangles across X or Y - xmin, ymin, xmax, ymax = cutout_obj.bounds() - px = 0.5 * (xmin + xmax) + margin - py = 0.5 * (ymin + ymax) + margin - lenghtx = (xmax - xmin) + (margin * 2) - lenghty = (ymax - ymin) + (margin * 2) - - gapsize = gapsize + (dia / 2) - - if isinstance(cutout_obj, FlatCAMGeometry): - # rename the obj name so it can be identified as cutout - cutout_obj.options["name"] += "_cutout" - elif isinstance(cutout_obj, FlatCAMGerber): - cutout_obj.isolate(dia=dia, passes=1, overlap=1, combine=False, outname="_temp") - ext_obj = self.app.collection.get_by_name("_temp") - - def geo_init(geo_obj, app_obj): - geo_obj.solid_geometry = obj_exteriors - - outname = cutout_obj.options["name"] + "_cutout" - - obj_exteriors = ext_obj.get_exteriors() - self.app.new_object('geometry', outname, geo_init) - - self.app.collection.set_all_inactive() - self.app.collection.set_active("_temp") - self.app.on_delete() - - cutout_obj = self.app.collection.get_by_name(outname) - else: - self.app.inform.emit("[ERROR]Cancelled. Object type is not supported.") - return - - try: - gaps_u = int(gaps) - except ValueError: - gaps_u = gaps - - if gaps_u == 8 or gaps_u == '2lr': - subtract_rectangle(cutout_obj, - xmin - gapsize, # botleft_x - py - gapsize + lenghty / 4, # botleft_y - xmax + gapsize, # topright_x - py + gapsize + lenghty / 4) # topright_y - subtract_rectangle(cutout_obj, - xmin - gapsize, - py - gapsize - lenghty / 4, - xmax + gapsize, - py + gapsize - lenghty / 4) - - if gaps_u == 8 or gaps_u == '2tb': - subtract_rectangle(cutout_obj, - px - gapsize + lenghtx / 4, - ymin - gapsize, - px + gapsize + lenghtx / 4, - ymax + gapsize) - subtract_rectangle(cutout_obj, - px - gapsize - lenghtx / 4, - ymin - gapsize, - px + gapsize - lenghtx / 4, - ymax + gapsize) - - if gaps_u == 4 or gaps_u == 'lr': - subtract_rectangle(cutout_obj, - xmin - gapsize, - py - gapsize, - xmax + gapsize, - py + gapsize) - - if gaps_u == 4 or gaps_u == 'tb': - subtract_rectangle(cutout_obj, - px - gapsize, - ymin - gapsize, - px + gapsize, - ymax + gapsize) - - cutout_obj.plot() - self.app.inform.emit("[success]Any-form Cutout operation finished.") diff --git a/tclCommands/TclCommandGeoCutout.py b/tclCommands/TclCommandGeoCutout.py index af12b54d..7067adc4 100644 --- a/tclCommands/TclCommandGeoCutout.py +++ b/tclCommands/TclCommandGeoCutout.py @@ -4,20 +4,23 @@ from tclCommands.TclCommand import TclCommandSignaled class TclCommandGeoCutout(TclCommandSignaled): """ - Tcl shell command to cut holding gaps from geometry. - """ + Tcl shell command to create a board cutout geometry. Allow cutout for any shape. Cuts holding gaps from geometry. - # array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon) - aliases = ['geocutout'] + example: - # Dictionary of types from Tcl command, needs to be ordered. - # For positional arguments + """ + + # List of all command aliases, to be able use old + # names for backward compatibility (add_poly, add_polygon) + aliases = ['geocutout', 'geoc'] + + # Dictionary of types from Tcl command, needs to be ordered arg_names = collections.OrderedDict([ - ('name', str) + ('name', str), ]) - # Dictionary of types from Tcl command, needs to be ordered. - # For options like -optionname value + # Dictionary of types from Tcl command, needs to be ordered, + # this is for options like -optionname value option_types = collections.OrderedDict([ ('dia', float), ('margin', float), @@ -30,99 +33,160 @@ class TclCommandGeoCutout(TclCommandSignaled): # structured help for current command, args needs to be ordered help = { - 'main': "Cut holding gaps from geometry.", + 'main': 'Creates board cutout from an object (Gerber or Geometry) of any shape', 'args': collections.OrderedDict([ - ('name', 'Name of the geometry object.'), + ('name', 'Name of the object.'), ('dia', 'Tool diameter.'), ('margin', 'Margin over bounds.'), - ('gapsize', 'Size of gap.'), - ('gaps', 'Type of gaps.'), + ('gapsize', 'size of gap.'), + ('gaps', "type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right, '2tb' = 2top-2bottom, " + "'2lr' = 2left-2right, '4' = 4 cuts, '8' = 8 cuts") ]), 'examples': [" #isolate margin for example from fritzing arduino shield or any svg etc\n" + - " isolate BCu_margin -dia 3 -overlap 1\n" + - "\n" + - " #create exteriors from isolated object\n" + - " exteriors BCu_margin_iso -outname BCu_margin_iso_exterior\n" + - "\n" + - " #delete isolated object if you dond need id anymore\n" + - " delete BCu_margin_iso\n" + - "\n" + - " #finally cut holding gaps\n" + - " geocutout BCu_margin_iso_exterior -dia 3 -gapsize 0.6 -gaps 4\n"] + " isolate BCu_margin -dia 3 -overlap 1\n" + + "\n" + + " #create exteriors from isolated object\n" + + " exteriors BCu_margin_iso -outname BCu_margin_iso_exterior\n" + + "\n" + + " #delete isolated object if you dond need id anymore\n" + + " delete BCu_margin_iso\n" + + "\n" + + " #finally cut holding gaps\n" + + " geocutout BCu_margin_iso_exterior -dia 3 -gapsize 0.6 -gaps 4\n"] } def execute(self, args, unnamed_args): """ - execute current TCL shell command - :param args: array of known named arguments and options - :param unnamed_args: array of other values which were passed into command - without -somename and we do not have them in known arg_names - :return: None or exception + :param args: + :param unnamed_args: + :return: """ - # How gaps wil be rendered: - # lr - left + right - # tb - top + bottom - # 4 - left + right +top + bottom - # 2lr - 2*left + 2*right - # 2tb - 2*top + 2*bottom - # 8 - 2*left + 2*right +2*top + 2*bottom - - name = args['name'] - obj = None - def subtract_rectangle(obj_, x0, y0, x1, y1): pts = [(x0, y0), (x1, y0), (x1, y1), (x0, y1)] obj_.subtract_polygon(pts) + if 'name' in args: + name = args['name'] + else: + self.app.inform.emit( + "[WARNING]The name of the object for which cutout is done is missing. Add it and retry.") + return + + if 'margin' in args: + margin = args['margin'] + else: + margin = 0.001 + + if 'dia' in args: + dia = args['dia'] + else: + dia = 0.1 + + if 'gaps' in args: + gaps = args['gaps'] + else: + gaps = 4 + + if 'gapsize' in args: + gapsize = args['gapsize'] + else: + gapsize = 0.1 + + # Get source object. try: - obj = self.app.collection.get_by_name(str(name)) + cutout_obj = self.app.collection.get_by_name(str(name)) except: - self.raise_tcl_error("Could not retrieve object: %s" % name) + return "Could not retrieve object: %s" % name + + if 0 in {dia}: + self.app.inform.emit("[WARNING]Tool Diameter is zero value. Change it to a positive integer.") + return "Tool Diameter is zero value. Change it to a positive integer." + + if gaps not in ['lr', 'tb', '2lr', '2tb', 4, 8]: + self.app.inform.emit("[WARNING]Gaps value can be only one of: 'lr', 'tb', '2lr', '2tb', 4 or 8. " + "Fill in a correct value and retry. ") + return # Get min and max data for each object as we just cut rectangles across X or Y - xmin, ymin, xmax, ymax = obj.bounds() - px = 0.5 * (xmin + xmax) - py = 0.5 * (ymin + ymax) - lenghtx = (xmax - xmin) - lenghty = (ymax - ymin) - gapsize = args['gapsize'] + (args['dia'] / 2) + xmin, ymin, xmax, ymax = cutout_obj.bounds() + px = 0.5 * (xmin + xmax) + margin + py = 0.5 * (ymin + ymax) + margin + lenghtx = (xmax - xmin) + (margin * 2) + lenghty = (ymax - ymin) + (margin * 2) - if args['gaps'] == '8' or args['gaps'] == '2lr': - subtract_rectangle(obj, + gapsize = gapsize + (dia / 2) + + if isinstance(cutout_obj, FlatCAMGeometry): + # rename the obj name so it can be identified as cutout + cutout_obj.options["name"] += "_cutout" + elif isinstance(cutout_obj, FlatCAMGerber): + + def geo_init(geo_obj, app_obj): + geo_obj.solid_geometry = obj_exteriors + + outname = cutout_obj.options["name"] + "_cutout" + cutout_obj.isolate(dia=dia, passes=1, overlap=1, combine=False, outname="_temp") + ext_obj = self.app.collection.get_by_name("_temp") + + try: + obj_exteriors = ext_obj.get_exteriors() + except: + obj_exteriors = ext_obj.solid_geometry + + self.app.new_object('geometry', outname, geo_init) + self.app.collection.set_all_inactive() + self.app.collection.set_active("_temp") + self.app.on_delete() + + cutout_obj = self.app.collection.get_by_name(outname) + else: + self.app.inform.emit("[ERROR]Cancelled. Object type is not supported.") + return + + try: + gaps_u = int(gaps) + except ValueError: + gaps_u = gaps + + if gaps_u == 8 or gaps_u == '2lr': + subtract_rectangle(cutout_obj, xmin - gapsize, # botleft_x py - gapsize + lenghty / 4, # botleft_y xmax + gapsize, # topright_x py + gapsize + lenghty / 4) # topright_y - subtract_rectangle(obj, + subtract_rectangle(cutout_obj, xmin - gapsize, py - gapsize - lenghty / 4, xmax + gapsize, py + gapsize - lenghty / 4) - if args['gaps'] == '8' or args['gaps'] == '2tb': - subtract_rectangle(obj, + if gaps_u == 8 or gaps_u == '2tb': + subtract_rectangle(cutout_obj, px - gapsize + lenghtx / 4, ymin - gapsize, px + gapsize + lenghtx / 4, ymax + gapsize) - subtract_rectangle(obj, + subtract_rectangle(cutout_obj, px - gapsize - lenghtx / 4, ymin - gapsize, px + gapsize - lenghtx / 4, ymax + gapsize) - if args['gaps'] == '4' or args['gaps'] == 'lr': - subtract_rectangle(obj, + if gaps_u == 4 or gaps_u == 'lr': + subtract_rectangle(cutout_obj, xmin - gapsize, py - gapsize, xmax + gapsize, py + gapsize) - if args['gaps'] == '4' or args['gaps'] == 'tb': - subtract_rectangle(obj, + if gaps_u == 4 or gaps_u == 'tb': + subtract_rectangle(cutout_obj, px - gapsize, ymin - gapsize, px + gapsize, ymax + gapsize) + + cutout_obj.plot() + self.app.inform.emit("[success]Any-form Cutout operation finished.") diff --git a/tclCommands/__init__.py b/tclCommands/__init__.py index 911a3203..b06014d7 100644 --- a/tclCommands/__init__.py +++ b/tclCommands/__init__.py @@ -12,7 +12,6 @@ import tclCommands.TclCommandAlignDrillGrid import tclCommands.TclCommandClearShell import tclCommands.TclCommandCncjob import tclCommands.TclCommandCutout -import tclCommands.TclCommandCutoutAny import tclCommands.TclCommandDelete import tclCommands.TclCommandDrillcncjob import tclCommands.TclCommandExportGcode