소스 검색

Merged in marius_stanciu/flatcam_beta/Beta (pull request #206)

Beta - Fixed a lot of Tcl Commands
Marius Stanciu 6 년 전
부모
커밋
279c2d6cc4
37개의 변경된 파일485개의 추가작업 그리고 200개의 파일을 삭제
  1. 102 58
      FlatCAMApp.py
  2. 49 37
      FlatCAMObj.py
  3. 1 1
      ObjectCollection.py
  4. 16 0
      README.md
  5. 3 2
      flatcamTools/ToolNonCopperClear.py
  6. 35 16
      flatcamTools/ToolPaint.py
  7. 28 30
      tclCommands/TclCommand.py
  8. 13 7
      tclCommands/TclCommandAlignDrill.py
  9. 11 5
      tclCommands/TclCommandAlignDrillGrid.py
  10. 1 1
      tclCommands/TclCommandBbox.py
  11. 3 2
      tclCommands/TclCommandCncjob.py
  12. 2 0
      tclCommands/TclCommandCopperClear.py
  13. 1 1
      tclCommands/TclCommandCutout.py
  14. 1 1
      tclCommands/TclCommandDrillcncjob.py
  15. 1 1
      tclCommands/TclCommandExteriors.py
  16. 2 2
      tclCommands/TclCommandGeoCutout.py
  17. 1 1
      tclCommands/TclCommandImportSvg.py
  18. 1 1
      tclCommands/TclCommandIsolate.py
  19. 1 1
      tclCommands/TclCommandJoinExcellon.py
  20. 1 1
      tclCommands/TclCommandJoinGeometry.py
  21. 1 1
      tclCommands/TclCommandMillDrills.py
  22. 1 1
      tclCommands/TclCommandMillSlots.py
  23. 0 1
      tclCommands/TclCommandMirror.py
  24. 1 1
      tclCommands/TclCommandNew.py
  25. 51 0
      tclCommands/TclCommandNewExcellon.py
  26. 6 4
      tclCommands/TclCommandNewGeometry.py
  27. 68 0
      tclCommands/TclCommandNewGerber.py
  28. 1 1
      tclCommands/TclCommandNregions.py
  29. 2 0
      tclCommands/TclCommandOpenExcellon.py
  30. 4 1
      tclCommands/TclCommandOpenGCode.py
  31. 5 12
      tclCommands/TclCommandOpenGerber.py
  32. 3 1
      tclCommands/TclCommandOpenProject.py
  33. 9 3
      tclCommands/TclCommandPaint.py
  34. 3 3
      tclCommands/TclCommandPanelize.py
  35. 2 2
      tclCommands/TclCommandPlotAll.py
  36. 51 0
      tclCommands/TclCommandPlotObjects.py
  37. 4 1
      tclCommands/__init__.py

+ 102 - 58
FlatCAMApp.py

@@ -844,6 +844,22 @@ class App(QtCore.QObject):
             "global_point_clipboard_format": "(%.4f, %.4f)",
             "global_zdownrate": None,
 
+            # autocomplete keywords
+            "global_autocomplete_keywords":
+                ['all', 'angle_x', 'angle_y', 'axis', 'axisoffset', 'box', 'center_x', 'center_y',
+                 'columns', 'combine', 'connect', 'contour', 'depthperpass', 'dia', 'diatol', 'dist',
+                 'drilled_dias', 'drillz', 'pp',
+                 'gridoffsety', 'gridx', 'gridy', 'has_offset', 'holes', 'margin', 'method',
+                 'milled_dias',
+                 'minoffset', 'multidepth', 'name', 'offset', 'opt_type', 'order', 'outname',
+                 'overlap', 'passes', 'postamble', 'ppname_e', 'ppname_g', 'preamble', 'radius', 'ref',
+                 'rest', 'rows', 'scale_factor', 'spacing_columns', 'spacing_rows', 'spindlespeed',
+                 'use_threads', 'value', 'x', 'x0', 'x1', 'y', 'y0', 'y1', 'z_cut', 'z_move',
+                 'default', 'feedrate_z', 'grbl_11', 'grbl_laser', 'hpgl', 'line_xyz', 'marlin',
+                 'Paste_1', 'Repetier', 'Toolchange_Custom', 'Roland_MDX_20', 'Toolchange_manual',
+                 'Toolchange_Probe_MACH3', 'dwell', 'dwelltime', 'toolchange_xy', 'iso_type',
+                 'Desktop', 'FlatPrj', 'FlatConfig', 'Users', 'Documents', 'My Documents', 'Marius'
+                 ],
             # General GUI Settings
             "global_hover": False,
             "global_selection_shape": True,
@@ -1898,27 +1914,13 @@ class App(QtCore.QObject):
                                   'mirror', 'ncc',
                                   'ncc_clear', 'ncr', 'new', 'new_geometry', 'non_copper_regions', 'offset',
                                   'open_excellon', 'open_gcode', 'open_gerber', 'open_project', 'options', 'paint',
-                                  'pan', 'panel', 'panelize', 'plot', 'save', 'save_project', 'save_sys', 'scale',
+                                  'pan', 'panel', 'panelize', 'plot_all', 'plot_objects', 'save', 'save_project',
+                                  'save_sys', 'scale',
                                   'set_active', 'set_sys', 'setsys', 'skew', 'subtract_poly', 'subtract_rectangle',
                                   'version', 'write_gcode'
                                   ]
 
-        self.ordinary_keywords = ['all', 'angle_x', 'angle_y', 'axis', 'axisoffset', 'box', 'center_x', 'center_y',
-                                  'columns', 'combine', 'connect', 'contour', 'depthperpass', 'dia', 'diatol', 'dist',
-                                  'drilled_dias', 'drillz', 'pp',
-                                  'endz', 'extracut', 'factor', 'False', 'false', 'feedrate', 'feedrate_rapid',
-                                  'filename', 'follow', 'gaps', 'gapsize', 'grid', 'gridoffset', 'gridoffsetx',
-                                  'gridoffsety', 'gridx', 'gridy', 'has_offset', 'holes', 'margin', 'method',
-                                  'milled_dias',
-                                  'minoffset', 'multidepth', 'name', 'offset', 'opt_type', 'order', 'outname',
-                                  'overlap', 'passes', 'postamble', 'ppname_e', 'ppname_g', 'preamble', 'radius', 'ref',
-                                  'rest', 'rows', 'scale_factor', 'spacing_columns', 'spacing_rows', 'spindlespeed',
-                                  'toolchange', 'toolchangez', 'tooldia', 'tools', 'travelz', 'True', 'true', 'type',
-                                  'use_threads', 'value', 'x', 'x0', 'x1', 'y', 'y0', 'y1', 'z_cut', 'z_move',
-                                  'default', 'feedrate_z', 'grbl_11', 'grbl_laser', 'hpgl', 'line_xyz', 'marlin',
-                                  'Paste_1', 'Repetier', 'Toolchange_Custom', 'Roland_MDX_20', 'Toolchange_manual',
-                                  'Toolchange_Probe_MACH3', 'dwell', 'dwelltime', 'toolchange_xy'
-                                  ]
+        self.ordinary_keywords = self.defaults["global_autocomplete_keywords"]
 
         self.tcl_keywords = [
             'after', 'append', 'apply', 'argc', 'argv', 'argv0', 'array', 'attemptckalloc', 'attemptckrealloc',
@@ -2253,6 +2255,10 @@ class App(QtCore.QObject):
         # Variable to store the GCODE that was edited
         self.gcode_edited = ""
 
+        # reference for the self.ui.code_editor
+        self.reference_code_editor = None
+        self.script_code = ''
+
         # if Preferences are changed in the Edit -> Preferences tab the value will be set to True
         self.preferences_changed_flag = False
 
@@ -3062,8 +3068,8 @@ class App(QtCore.QObject):
         result = self.exec_command_test(text, False)
 
         # MS: added this method call so the geometry is updated once the TCL command is executed
-        if no_plot is None:
-            self.plot_all()
+        # if no_plot is None:
+        #     self.plot_all()
 
         return result
 
@@ -5913,11 +5919,11 @@ class App(QtCore.QObject):
         if self.ui.shell_dock.isHidden():
             self.ui.shell_dock.show()
 
-        script_code = self.ui.code_editor.toPlainText()
+        self.script_code = deepcopy(self.ui.code_editor.toPlainText())
         # self.shell._sysShell.exec_command(script_code)
 
         old_line = ''
-        for tcl_command_line in script_code.splitlines():
+        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
@@ -5940,17 +5946,16 @@ class App(QtCore.QObject):
                         self.shell.append_output(result + '\n')
 
                     old_line = ''
-                except tk.TclError as e:
+                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.tcl.eval("set errorInfo")
             self.log.error("Exec command Exception: %s" % (result + '\n'))
             self.shell.append_error('ERROR: ' + result + '\n')
-        else:
-            # success! plot all objects
-            self.plot_all()
 
         self.shell.close_proccessing()
 
@@ -7520,7 +7525,7 @@ class App(QtCore.QObject):
         self.inform.emit('[success] %s...' %
                          _("New Project created"))
 
-    def on_file_new(self):
+    def on_file_new(self, cli=None):
         """
         Callback for menu item File->New. Returns the application to its
         startup state. This method is thread-safe.
@@ -7580,15 +7585,16 @@ class App(QtCore.QObject):
         # Init Tools
         self.init_tools()
 
-        # Close any Tabs opened in the Plot Tab Area section
-        for index in range(self.ui.plot_tab_area.count()):
-            self.ui.plot_tab_area.closeTab(index)
-            # for whatever reason previous command does not close the last tab so I do it manually
-        self.ui.plot_tab_area.closeTab(0)
+        if cli is None:
+            # Close any Tabs opened in the Plot Tab Area section
+            for index in range(self.ui.plot_tab_area.count()):
+                self.ui.plot_tab_area.closeTab(index)
+                # for whatever reason previous command does not close the last tab so I do it manually
+            self.ui.plot_tab_area.closeTab(0)
 
-        # # And then add again the Plot Area
-        self.ui.plot_tab_area.addTab(self.ui.plot_tab, "Plot Area")
-        self.ui.plot_tab_area.protectTab(0)
+            # # And then add again the Plot Area
+            self.ui.plot_tab_area.addTab(self.ui.plot_tab, "Plot Area")
+            self.ui.plot_tab_area.protectTab(0)
 
         # take the focus of the Notebook on Project Tab.
         self.ui.notebook.setCurrentWidget(self.ui.project_tab)
@@ -8199,6 +8205,9 @@ class App(QtCore.QObject):
         self.ui.code_editor.completer_enable = False
         self.ui.buttonRun.hide()
 
+        # make sure to keep a reference to the code editor
+        self.reference_code_editor = self.ui.code_editor
+
         # Switch plot_area to CNCJob tab
         self.ui.plot_tab_area.setCurrentWidget(self.ui.cncjob_tab)
 
@@ -8217,20 +8226,34 @@ class App(QtCore.QObject):
 
         if obj.kind == 'gerber':
             flt = "Gerber Files (*.GBR);;All Files (*.*)"
-        else:
+        elif obj.kind == 'excellon':
             flt = "Excellon Files (*.DRL);;All Files (*.*)"
+        elif obj.kind == 'cncjob':
+            "GCode Files (*.NC);;All Files (*.*)"
+        else:
+            flt = "All Files (*.*)"
 
         self.init_code_editor(name=_("Source Editor"))
         self.ui.buttonOpen.clicked.connect(lambda: self.handleOpen(filt=flt))
         self.ui.buttonSave.clicked.connect(lambda: self.handleSaveGCode(filt=flt))
 
         # then append the text from GCode to the text editor
-        try:
-            file = StringIO(obj.source_file)
-        except AttributeError:
-            self.inform.emit('[WARNING_NOTCL] %s' %
-                             _("There is no selected object for which to see it's source file code."))
-            return 'fail'
+        if obj.kind == 'cncjob':
+            try:
+                file = obj.export_gcode(preamble='', postamble='', to_file=True)
+                if file == 'fail':
+                    return 'fail'
+            except AttributeError:
+                self.inform.emit('[WARNING_NOTCL] %s' %
+                                 _("There is no selected object for which to see it's source file code."))
+                return 'fail'
+        else:
+            try:
+                file = StringIO(obj.source_file)
+            except AttributeError:
+                self.inform.emit('[WARNING_NOTCL] %s' %
+                                 _("There is no selected object for which to see it's source file code."))
+                return 'fail'
 
         self.ui.cncjob_frame.hide()
         try:
@@ -8287,6 +8310,10 @@ class App(QtCore.QObject):
         self.ui.buttonOpen.clicked.connect(lambda: self.handleOpen(filt=flt))
         self.ui.buttonSave.clicked.connect(lambda: self.handleSaveGCode(filt=flt))
         self.ui.buttonRun.show()
+        try:
+            self.ui.buttonRun.clicked.disconnect(self.handleRunCode)
+        except TypeError:
+            pass
         self.ui.buttonRun.clicked.connect(self.handleRunCode)
 
         self.handleTextChanged()
@@ -9373,7 +9400,7 @@ class App(QtCore.QObject):
             self.inform.emit('[success] %s: %s' %
                              (_("Opened"), filename))
 
-    def open_excellon(self, filename, outname=None):
+    def open_excellon(self, filename, outname=None, plot=True):
         """
         Opens an Excellon file, parses it and creates a new object for
         it in the program. Thread-safe.
@@ -9427,7 +9454,7 @@ class App(QtCore.QObject):
 
             # Object name
             name = outname or filename.split('/')[-1].split('\\')[-1]
-            ret_val = self.new_object("excellon", name, obj_init, autoselected=False)
+            ret_val = self.new_object("excellon", name, obj_init, autoselected=False, plot=plot)
             if ret_val == 'fail':
                 self.inform.emit('[ERROR_NOTCL] %s' %
                                  _('Open Excellon file failed. Probable not an Excellon file.'))
@@ -9440,7 +9467,7 @@ class App(QtCore.QObject):
             self.inform.emit('[success] %s: %s' %
                              (_("Opened"), filename))
 
-    def open_gcode(self, filename, outname=None):
+    def open_gcode(self, filename, outname=None, plot=True):
         """
         Opens a G-gcode file, parses it and creates a new object for
         it in the program. Thread-safe.
@@ -9492,7 +9519,7 @@ class App(QtCore.QObject):
             name = outname or filename.split('/')[-1].split('\\')[-1]
 
             # New object creation and file processing
-            ret = self.new_object("cncjob", name, obj_init, autoselected=False)
+            ret = self.new_object("cncjob", name, obj_init, autoselected=False, plot=plot)
             if ret == 'fail':
                 self.inform.emit('[ERROR_NOTCL] %s' %
                                  _("Failed to create CNCJob Object. Probable not a GCode file.\n "
@@ -9540,7 +9567,7 @@ class App(QtCore.QObject):
                              (_("Failed to open config file"), filename))
             return
 
-    def open_project(self, filename, run_from_arg=None):
+    def open_project(self, filename, run_from_arg=None, plot=True, cli=None):
         """
         Loads a project from the specified file.
 
@@ -9549,16 +9576,21 @@ class App(QtCore.QObject):
         3) Calls on_file_new()
         4) Updates options
         5) Calls new_object() with the object's from_dict() as init method.
-        6) Calls plot_all()
+        6) Calls plot_all() if plot=True
 
         :param filename:  Name of the file from which to load.
         :type filename: str
         :param run_from_arg: True if run for arguments
+        :param plot: If True plot all objects in the project
+        :param cli: run from command line
         :return: None
         """
         App.log.debug("Opening project: " + filename)
 
-        self.set_ui_title(name=_("Loading Project ... Please Wait ..."))
+        # for some reason, setting ui_title does not work when this method is called from Tcl Shell
+        # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
+        if cli is None:
+            self.set_ui_title(name=_("Loading Project ... Please Wait ..."))
 
         # Open and parse an uncompressed Project file
         try:
@@ -9581,7 +9613,6 @@ class App(QtCore.QObject):
                 with lzma.open(filename) as f:
                     file_content = f.read().decode('utf-8')
                     d = json.loads(file_content, object_hook=dict2obj)
-
             except Exception as e:
                 App.log.error("Failed to open project file: %s with error: %s" % (filename, str(e)))
                 self.inform.emit('[ERROR_NOTCL] %s: %s' %
@@ -9592,13 +9623,19 @@ class App(QtCore.QObject):
         # # NOT THREAD SAFE # ##
         if run_from_arg is True:
             pass
+        elif cli is True:
+            self.delete_selection_shape()
         else:
             self.on_file_new()
 
         # Project options
         self.options.update(d['options'])
         self.project_filename = filename
-        self.set_screen_units(self.options["units"])
+
+        # for some reason, setting ui_title does not work when this method is called from Tcl Shell
+        # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
+        if cli is None:
+            self.set_screen_units(self.options["units"])
 
         # Re create objects
         App.log.debug(" **************** Started PROEJCT loading... **************** ")
@@ -9606,24 +9643,31 @@ class App(QtCore.QObject):
         for obj in d['objs']:
             def obj_init(obj_inst, app_inst):
                 obj_inst.from_dict(obj)
+
             App.log.debug("Recreating from opened project an %s object: %s" %
                           (obj['kind'].capitalize(), obj['options']['name']))
 
-            self.set_ui_title(name="{} {}: {}".format(_("Loading Project ... restoring"),
-                                                      obj['kind'].upper(),
-                                                      obj['options']['name']
-                                                      )
-                              )
+            # for some reason, setting ui_title does not work when this method is called from Tcl Shell
+            # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
+            if cli is None:
+                self.set_ui_title(name="{} {}: {}".format(_("Loading Project ... restoring"),
+                                                          obj['kind'].upper(),
+                                                          obj['options']['name']
+                                                          )
+                                  )
 
-            self.new_object(obj['kind'], obj['options']['name'], obj_init, active=False, fit=False, plot=True)
+            self.new_object(obj['kind'], obj['options']['name'], obj_init, active=False, fit=False, plot=plot)
 
-        # self.plot_all()
         self.inform.emit('[success] %s: %s' %
                          (_("Project loaded from"), filename))
 
         self.should_we_save = False
         self.file_opened.emit("project", filename)
-        self.set_ui_title(name=self.project_filename)
+
+        # for some reason, setting ui_title does not work when this method is called from Tcl Shell
+        # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
+        if cli is None:
+            self.set_ui_title(name=self.project_filename)
 
         App.log.debug(" **************** Finished PROJECT loading... **************** ")
 

+ 49 - 37
FlatCAMObj.py

@@ -923,8 +923,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
         except Exception as e:
             return "Operation failed: %s" % str(e)
 
-    def isolate(self, iso_type=None, dia=None, passes=None, overlap=None,
-                outname=None, combine=None, milling_type=None, follow=None):
+    def isolate(self, iso_type=None, dia=None, passes=None, overlap=None, outname=None, combine=None,
+                milling_type=None, follow=None, plot=True):
         """
         Creates an isolation routing geometry object in the project.
 
@@ -947,13 +947,13 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
             combine = bool(combine)
         if milling_type is None:
             milling_type = self.options["milling_type"]
+
         if iso_type is None:
             self.iso_type = 2
         else:
             self.iso_type = iso_type
 
-        base_name = self.options["name"] + "_iso"
-        base_name = outname or base_name
+        base_name = self.options["name"]
 
         def generate_envelope(offset, invert, envelope_iso_type=2, follow=None, passes=0):
             # isolation_geometry produces an envelope that is going on the left of the geometry
@@ -1061,12 +1061,15 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
             return new_geometry
 
         if combine:
-            if self.iso_type == 0:
-                iso_name = self.options["name"] + "_ext_iso"
-            elif self.iso_type == 1:
-                iso_name = self.options["name"] + "_int_iso"
+            if outname is None:
+                if self.iso_type == 0:
+                    iso_name = base_name + "_ext_iso"
+                elif self.iso_type == 1:
+                    iso_name = base_name + "_int_iso"
+                else:
+                    iso_name = base_name + "_iso"
             else:
-                iso_name = base_name
+                iso_name = outname
 
             # TODO: This is ugly. Create way to pass data into init function.
             def iso_init(geo_obj, app_obj):
@@ -1161,25 +1164,31 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
                     geo_obj.solid_geometry = area_subtraction(geo_obj.solid_geometry)
 
             # TODO: Do something if this is None. Offer changing name?
-            self.app.new_object("geometry", iso_name, iso_init)
+            self.app.new_object("geometry", iso_name, iso_init, plot=plot)
         else:
             for i in range(passes):
 
                 offset = dia * ((2 * i + 1) / 2.0) - (i * overlap * dia)
                 if passes > 1:
-                    if self.iso_type == 0:
-                        iso_name = self.options["name"] + "_ext_iso" + str(i + 1)
-                    elif self.iso_type == 1:
-                        iso_name = self.options["name"] + "_int_iso" + str(i + 1)
+                    if outname is None:
+                        if self.iso_type == 0:
+                            iso_name = base_name + "_ext_iso" + str(i + 1)
+                        elif self.iso_type == 1:
+                            iso_name = base_name + "_int_iso" + str(i + 1)
+                        else:
+                            iso_name = base_name + "_iso" + str(i + 1)
                     else:
-                        iso_name = base_name + str(i + 1)
+                        iso_name = outname
                 else:
-                    if self.iso_type == 0:
-                        iso_name = self.options["name"] + "_ext_iso"
-                    elif self.iso_type == 1:
-                        iso_name = self.options["name"] + "_int_iso"
+                    if outname is None:
+                        if self.iso_type == 0:
+                            iso_name = base_name + "_ext_iso"
+                        elif self.iso_type == 1:
+                            iso_name = base_name + "_int_iso"
+                        else:
+                            iso_name = base_name + "_iso"
                     else:
-                        iso_name = base_name
+                        iso_name = outname
 
                 # TODO: This is ugly. Create way to pass data into init function.
                 def iso_init(geo_obj, app_obj):
@@ -1230,7 +1239,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
                         geo_obj.solid_geometry = area_subtraction(geo_obj.solid_geometry)
 
                 # TODO: Do something if this is None. Offer changing name?
-                self.app.new_object("geometry", iso_name, iso_init)
+                self.app.new_object("geometry", iso_name, iso_init, plot=plot)
 
     def on_plot_cb_click(self, *args):
         if self.muted_ui:
@@ -2595,7 +2604,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
 
         return has_slots, excellon_code
 
-    def generate_milling_drills(self, tools=None, outname=None, tooldia=None, use_thread=False):
+    def generate_milling_drills(self, tools=None, outname=None, tooldia=None, plot=False, use_thread=False):
         """
         Note: This method is a good template for generic operations as
         it takes it's options from parameters or otherwise from the
@@ -2674,7 +2683,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
                             Point(hole['point']).buffer(buffer_value).exterior)
         if use_thread:
             def geo_thread(app_obj):
-                app_obj.new_object("geometry", outname, geo_init)
+                app_obj.new_object("geometry", outname, geo_init, plot=plot)
                 app_obj.progress.emit(100)
 
             # Create a promise with the new name
@@ -2683,11 +2692,11 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             # Send to worker
             self.app.worker_task.emit({'fcn': geo_thread, 'params': [self.app]})
         else:
-            self.app.new_object("geometry", outname, geo_init)
+            self.app.new_object("geometry", outname, geo_init, plot=plot)
 
         return True, ""
 
-    def generate_milling_slots(self, tools=None, outname=None, tooldia=None, use_thread=False):
+    def generate_milling_slots(self, tools=None, outname=None, tooldia=None, plot=True, use_thread=False):
         """
         Note: This method is a good template for generic operations as
         it takes it's options from parameters or otherwise from the
@@ -2781,7 +2790,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
 
         if use_thread:
             def geo_thread(app_obj):
-                app_obj.new_object("geometry", outname + '_slot', geo_init)
+                app_obj.new_object("geometry", outname + '_slot', geo_init, plot=plot)
                 app_obj.progress.emit(100)
 
             # Create a promise with the new name
@@ -2790,7 +2799,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             # Send to worker
             self.app.worker_task.emit({'fcn': geo_thread, 'params': [self.app]})
         else:
-            self.app.new_object("geometry", outname + '_slot', geo_init)
+            self.app.new_object("geometry", outname + '_slot', geo_init, plot=plot)
 
         return True, ""
 
@@ -4518,7 +4527,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             self.app.inform.emit('[ERROR_NOTCL] %s' %
                                  _("Failed. No tool selected in the tool table ..."))
 
-    def mtool_gen_cncjob(self, outname=None, tools_dict=None, tools_in_use=None, segx=None, segy=None, use_thread=True):
+    def mtool_gen_cncjob(self, outname=None, tools_dict=None, tools_in_use=None, segx=None, segy=None,
+                         plot=True, use_thread=True):
         """
         Creates a multi-tool CNCJob out of this Geometry object.
         The actual work is done by the target FlatCAMCNCjob object's
@@ -4875,7 +4885,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             def job_thread(app_obj):
                 if self.solid_geometry:
                     with self.app.proc_container.new(_("Generating CNC Code")):
-                        if app_obj.new_object("cncjob", outname, job_init_single_geometry) != 'fail':
+                        if app_obj.new_object("cncjob", outname, job_init_single_geometry, plot=plot) != 'fail':
                             app_obj.inform.emit('[success] %s: %s' %
                                                 (_("CNCjob created")), outname)
                             app_obj.progress.emit(100)
@@ -4892,9 +4902,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
         else:
             if self.solid_geometry:
-                self.app.new_object("cncjob", outname, job_init_single_geometry)
+                self.app.new_object("cncjob", outname, job_init_single_geometry, plot=plot)
             else:
-                self.app.new_object("cncjob", outname, job_init_multi_geometry)
+                self.app.new_object("cncjob", outname, job_init_multi_geometry, plot=plot)
 
     def generatecncjob(
             self, outname=None,
@@ -4907,7 +4917,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             extracut=None, startz=None, endz=None,
             ppname_g=None,
             segx=None, segy=None,
-            use_thread=True):
+            use_thread=True,
+            plot=True):
         """
         Only used for TCL Command.
         Creates a CNCJob out of this Geometry object. The actual
@@ -5034,7 +5045,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             # To be run in separate thread
             def job_thread(app_obj):
                 with self.app.proc_container.new(_("Generating CNC Code")):
-                    app_obj.new_object("cncjob", outname, job_init)
+                    app_obj.new_object("cncjob", outname, job_init, plot=plot)
                     app_obj.inform.emit('[success] %s: %s' %
                                         (_("CNCjob created")), outname)
                     app_obj.progress.emit(100)
@@ -5044,7 +5055,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             # Send to worker
             self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
         else:
-            self.app.new_object("cncjob", outname, job_init)
+            self.app.new_object("cncjob", outname, job_init, plot=plot)
 
     # def on_plot_cb_click(self, *args):  # TODO: args not needed
     #     if self.muted_ui:
@@ -5833,11 +5844,12 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
 
         preamble = str(self.ui.prepend_text.get_value())
         postamble = str(self.ui.append_text.get_value())
-        gc = self.export_gcode(preamble=preamble, postamble=postamble, to_file=True)
-        if gc == 'fail':
+
+        gco = self.export_gcode(preamble=preamble, postamble=postamble, to_file=True)
+        if gco == 'fail':
             return
         else:
-            self.app.gcode_edited = gc
+            self.app.gcode_edited = gco
 
         self.app.init_code_editor(name=_("Code Editor"))
         self.app.ui.buttonOpen.clicked.connect(self.app.handleOpen)

+ 1 - 1
ObjectCollection.py

@@ -320,7 +320,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
                     self.app.ui.menuprojectgeneratecnc.setVisible(False)
                 if type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon and type(obj) != FlatCAMGerber:
                     self.app.ui.menuprojectedit.setVisible(False)
-                if type(obj) != FlatCAMGerber and type(obj) != FlatCAMExcellon:
+                if type(obj) != FlatCAMGerber and type(obj) != FlatCAMExcellon and type(obj) != FlatCAMCNCjob:
                     self.app.ui.menuprojectviewsource.setVisible(False)
         else:
             self.app.ui.menuprojectgeneratecnc.setVisible(False)

+ 16 - 0
README.md

@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
 
 =================================================
 
+16.09.2019
+
+- modified the TclCommand New so it will no longer close all tabs when called (it closed the Code Editor tab which may have been holding the code that run)
+
 15.09.2019
 
 - refactored FlatCAMGeometry.mtool_gen_cncjob() method
@@ -19,6 +23,18 @@ CAD program, and create G-Code for Isolation routing.
 - finished updating the TclCommand cncjob to work for multi-geo Geometry objects with the parameters from the args
 - fixed the TclCommand cncjob to use the -outname parameter
 - added some more keywords in the data_model for auto-completer
+- fixed isolate TclCommand to use correctly the -outname parameter
+- added possibility to see the GCode when right clicking on the Project tab on a CNCJob object and then clicking View Source
+- added a new TclCommand named PlotObjects which will plot a list of FlatCAM objects
+- made that after opening an object in FlatCAM it is not automatically plotted. If the user wants to plot it can use the TclCommands PlotAll or PlotObjects
+- modified the TclCommands so that open files do not plot the opened files automatically
+- made all TclCommands not to be plotted automatically
+- made sure that all TclCommands are not threaded
+- added new TclCommands: NewExcellon, NewGerber
+- fixed the TclCommand open_project
+- added the outname parameter (and established an default name when outname not used) for the AlignDrillGrid and AlignDrill TclCommands
+- fixed Scripts repeating multiple time when the Code Editor is used. This repetition was correlated with multiple openings of the Code Editor window (especially after an error)
+- added the autocomplete keywords that can be changed to the defaults dictionary
 
 14.09.2019
 

+ 3 - 2
flatcamTools/ToolNonCopperClear.py

@@ -1292,6 +1292,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
                      method=None,
                      rest=None,
                      tools_storage=None,
+                     plot=True,
                      run_threaded=True):
         """
         Clear the excess copper from the entire object.
@@ -2189,9 +2190,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
         def job_thread(app_obj):
             try:
                 if rest_machining_choice is True:
-                    app_obj.new_object("geometry", name, gen_clear_area_rest)
+                    app_obj.new_object("geometry", name, gen_clear_area_rest, plot=plot)
                 else:
-                    app_obj.new_object("geometry", name, gen_clear_area)
+                    app_obj.new_object("geometry", name, gen_clear_area, plot=plot)
             except FlatCAMApp.GracefulException:
                 proc.done()
                 return

+ 35 - 16
flatcamTools/ToolPaint.py

@@ -1168,7 +1168,9 @@ class ToolPaint(FlatCAMTool, Gerber):
                    outname=None,
                    connect=None,
                    contour=None,
-                   tools_storage=None):
+                   tools_storage=None,
+                   plot=True,
+                   run_threaded=True):
         """
         Paints a polygon selected by clicking on its interior or by having a point coordinates given
 
@@ -1432,7 +1434,7 @@ class ToolPaint(FlatCAMTool, Gerber):
 
         def job_thread(app_obj):
             try:
-                app_obj.new_object("geometry", name, gen_paintarea)
+                app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
             except FlatCAMApp.GracefulException:
                 proc.done()
                 return
@@ -1451,8 +1453,11 @@ class ToolPaint(FlatCAMTool, Gerber):
         # Promise object with the new name
         self.app.collection.promise(name)
 
-        # Background
-        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        if run_threaded:
+            # Background
+            self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        else:
+            job_thread(app_obj=self.app)
 
     def paint_poly_all(self, obj,
                        tooldia=None,
@@ -1463,7 +1468,9 @@ class ToolPaint(FlatCAMTool, Gerber):
                        outname=None,
                        connect=None,
                        contour=None,
-                       tools_storage=None):
+                       tools_storage=None,
+                       plot=True,
+                       run_threaded=True):
         """
         Paints all polygons in this object.
 
@@ -1901,9 +1908,9 @@ class ToolPaint(FlatCAMTool, Gerber):
         def job_thread(app_obj):
             try:
                 if self.rest_cb.isChecked():
-                    app_obj.new_object("geometry", name, gen_paintarea_rest_machining)
+                    app_obj.new_object("geometry", name, gen_paintarea_rest_machining, plot=plot)
                 else:
-                    app_obj.new_object("geometry", name, gen_paintarea)
+                    app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
             except FlatCAMApp.GracefulException:
                 proc.done()
                 return
@@ -1920,8 +1927,11 @@ class ToolPaint(FlatCAMTool, Gerber):
         # Promise object with the new name
         self.app.collection.promise(name)
 
-        # Background
-        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        if run_threaded:
+            # Background
+            self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        else:
+            job_thread(app_obj=self.app)
 
     def paint_poly_area(self, obj, sel_obj,
                         tooldia=None,
@@ -1932,7 +1942,9 @@ class ToolPaint(FlatCAMTool, Gerber):
                         outname=None,
                         connect=None,
                         contour=None,
-                        tools_storage=None):
+                        tools_storage=None,
+                        plot=True,
+                        run_threaded=True):
         """
         Paints all polygons in this object that are within the sel_obj object
 
@@ -2366,9 +2378,9 @@ class ToolPaint(FlatCAMTool, Gerber):
         def job_thread(app_obj):
             try:
                 if self.rest_cb.isChecked():
-                    app_obj.new_object("geometry", name, gen_paintarea_rest_machining)
+                    app_obj.new_object("geometry", name, gen_paintarea_rest_machining, plot=plot)
                 else:
-                    app_obj.new_object("geometry", name, gen_paintarea)
+                    app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
             except FlatCAMApp.GracefulException:
                 proc.done()
                 return
@@ -2385,8 +2397,11 @@ class ToolPaint(FlatCAMTool, Gerber):
         # Promise object with the new name
         self.app.collection.promise(name)
 
-        # Background
-        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        if run_threaded:
+            # Background
+            self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        else:
+            job_thread(app_obj=self.app)
 
     def paint_poly_ref(self, obj, sel_obj,
                        tooldia=None,
@@ -2397,7 +2412,9 @@ class ToolPaint(FlatCAMTool, Gerber):
                        outname=None,
                        connect=None,
                        contour=None,
-                       tools_storage=None):
+                       tools_storage=None,
+                       plot=True,
+                       run_threaded=True):
         """
         Paints all polygons in this object that are within the sel_obj object
 
@@ -2441,7 +2458,9 @@ class ToolPaint(FlatCAMTool, Gerber):
                              outname=outname,
                              connect=connect,
                              contour=contour,
-                             tools_storage=tools_storage)
+                             tools_storage=tools_storage,
+                             plot=plot,
+                             run_threaded=run_threaded)
 
     @staticmethod
     def paint_bounds(geometry):

+ 28 - 30
tclCommands/TclCommand.py

@@ -78,8 +78,7 @@ class TclCommand(object):
 
         :return: current command
         """
-
-        command_string = []
+        command_string = list()
         command_string.append(self.aliases[0])
 
         if self.original_args is not None:
@@ -117,7 +116,7 @@ class TclCommand(object):
             if help_key in self.arg_names:
                 arg_type = self.arg_names[help_key]
                 type_name = str(arg_type.__name__)
-                #in_command_name = help_key + "<" + type_name + ">"
+                # in_command_name = help_key + "<" + type_name + ">"
                 in_command_name = help_key
 
             elif help_key in self.option_types:
@@ -163,35 +162,36 @@ class TclCommand(object):
 
     @staticmethod
     def parse_arguments(args):
-            """
-            Pre-processes arguments to detect '-keyword value' pairs into dictionary
-            and standalone parameters into list.
+        """
+        Pre-processes arguments to detect '-keyword value' pairs into dictionary
+        and standalone parameters into list.
 
-            This is copy from FlatCAMApp.setup_shell().h() just for accessibility,
-            original should  be removed  after all commands will be converted
+        This is copy from FlatCAMApp.setup_shell().h() just for accessibility,
+        original should  be removed  after all commands will be converted
 
-            :param args: arguments from tcl to parse
-            :return: arguments, options
-            """
+        :param args: arguments from tcl to parse
+        :return: arguments, options
+        """
 
-            options = {}
-            arguments = []
-            n = len(args)
-            name = None
-            for i in range(n):
-                match = re.search(r'^-([a-zA-Z].*)', args[i])
-                if match:
-                    assert name is None
-                    name = match.group(1)
-                    continue
-
-                if name is None:
-                    arguments.append(args[i])
-                else:
-                    options[name] = args[i]
-                    name = None
+        options = {}
+        arguments = []
+        n = len(args)
 
-            return arguments, options
+        name = None
+        for i in range(n):
+            match = re.search(r'^-([a-zA-Z].*)', args[i])
+            if match:
+                assert name is None
+                name = match.group(1)
+                continue
+
+            if name is None:
+                arguments.append(args[i])
+            else:
+                options[name] = args[i]
+                name = None
+
+        return arguments, options
 
     def check_args(self, args):
         """
@@ -274,7 +274,6 @@ class TclCommand(object):
         """
 
         # self.worker_task.emit({'fcn': self.exec_command_test, 'params': [text, False]})
-
         try:
             self.log.debug("TCL command '%s' executed." % str(self.__class__))
             self.original_args = args
@@ -416,7 +415,6 @@ class TclCommandSignaled(TclCommand):
                 # when operation  will be  really long is good  to set it higher then defqault 30s
                 self.app.worker_task.emit({'fcn': self.execute_call, 'params': [args, unnamed_args]})
 
-
             return self.output
 
         except Exception as unknown:

+ 13 - 7
tclCommands/TclCommandAlignDrill.py

@@ -29,6 +29,7 @@ class TclCommandAlignDrill(TclCommandSignaled):
         ('axisoffset', float),
         ('dia', float),
         ('dist', float),
+        ('outname', str),
     ])
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -47,9 +48,11 @@ class TclCommandAlignDrill(TclCommandSignaled):
             ('minoffset', 'min and max distance between align hole and pcb.'),
             ('axisoffset', 'Offset on second axis before aligment holes'),
             ('axis', 'Mirror axis parallel to the X or Y axis.'),
-            ('dist', 'Distance of the mirror axis to the X or Y axis.')
+            ('dist', 'Distance of the mirror axis to the X or Y axis.'),
+            ('outname', 'Name of the resulting Excellon object.'),
         ]),
-        'examples': []
+        'examples': ['aligndrill my_object -axis X -box my_object -dia 3.125 -grid 1 '
+                     '-gridoffset 0 -minoffset 2 -axisoffset 2']
     }
 
     def execute(self, args, unnamed_args):
@@ -64,6 +67,11 @@ class TclCommandAlignDrill(TclCommandSignaled):
 
         name = args['name']
 
+        if 'outname' in args:
+            outname = args['outname']
+        else:
+            outname = name + "_aligndrill"
+
         # Get source object.
         try:
             obj = self.app.collection.get_by_name(str(name))
@@ -176,9 +184,7 @@ class TclCommandAlignDrill(TclCommandSignaled):
                 px = 0.5 * (xmin + xmax)
                 py = 0.5 * (ymin + ymax)
 
-                obj.app.new_object("excellon",
-                                   name + "_aligndrill",
-                                   alligndrill_init_me)
+                obj.app.new_object("excellon", outname, alligndrill_init_me, plot=False)
 
             except Exception as e:
                 return "Operation failed: %s" % str(e)
@@ -194,8 +200,8 @@ class TclCommandAlignDrill(TclCommandSignaled):
             try:
                 px = dist
                 py = dist
-                obj.app.new_object("excellon", name + "_alligndrill", alligndrill_init_me)
+                obj.app.new_object("excellon", outname, alligndrill_init_me, plot=False)
             except Exception as e:
                 return "Operation failed: %s" % str(e)
 
-        return 'Ok'
+        return 'Ok. Align Drills Excellon object created'

+ 11 - 5
tclCommands/TclCommandAlignDrillGrid.py

@@ -17,7 +17,7 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
     # Dictionary of types from Tcl command, needs to be ordered.
     # For positional arguments
     arg_names = collections.OrderedDict([
-        ('outname', str)
+
     ])
 
     # Dictionary of types from Tcl command, needs to be ordered.
@@ -29,11 +29,12 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
         ('gridy', float),
         ('gridoffsety', float),
         ('columns', int),
-        ('rows', int)
+        ('rows', int),
+        ('outname', str)
     ])
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
-    required = ['outname', 'gridx', 'gridy', 'columns', 'rows']
+    required = ['gridx', 'gridy', 'columns', 'rows']
 
     # structured help for current command, args needs to be ordered
     help = {
@@ -48,7 +49,7 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
             ('colums', 'Number of grid holes on X axis.'),
             ('rows', 'Number of grid holes on Y axis.'),
         ]),
-        'examples': []
+        'examples': ['aligndrillgrid -rows 2 -columns 2 -gridoffsetx 10 -gridoffsety 10 -gridx 2.54 -gridy 5.08']
     }
 
     def execute(self, args, unnamed_args):
@@ -61,6 +62,11 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
         :return: None or exception
         """
 
+        if 'outname' in args:
+            outname = args['outname']
+        else:
+            outname = "new_aligndrill_grid"
+
         if 'gridoffsetx' not in args:
             gridoffsetx = 0
         else:
@@ -102,4 +108,4 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
             init_obj.create_geometry()
 
         # Create the new object
-        self.app.new_object("excellon", args['outname'], aligndrillgrid_init_me)
+        self.app.new_object("excellon", outname, aligndrillgrid_init_me, plot=False)

+ 1 - 1
tclCommands/TclCommandBbox.py

@@ -90,6 +90,6 @@ class TclCommandBbox(TclCommand):
                     bounding_box = bounding_box.envelope
                 geo_obj.solid_geometry = bounding_box
 
-            self.app.new_object("geometry", args['outname'], geo_init)
+            self.app.new_object("geometry", args['outname'], geo_init, plot=False)
         except Exception as e:
             return "Operation failed: %s" % str(e)

+ 3 - 2
tclCommands/TclCommandCncjob.py

@@ -143,7 +143,7 @@ class TclCommandCncjob(TclCommandSignaled):
         obj.options['multidepth'] = False
 
         if not obj.multigeo:
-            obj.generatecncjob(use_thread=False, **args)
+            obj.generatecncjob(use_thread=False, plot=False, **args)
         else:
             # Update the local_tools_dict values with the args value
             local_tools_dict = deepcopy(obj.tools)
@@ -171,5 +171,6 @@ class TclCommandCncjob(TclCommandSignaled):
                 outname=args['outname'],
                 tools_dict=local_tools_dict,
                 tools_in_use=[],
-                use_thread=False)
+                use_thread=False,
+                plot=False)
             # self.raise_tcl_error('The object is a multi-geo geometry which is not supported in cncjob Tcl Command')

+ 2 - 0
tclCommands/TclCommandCopperClear.py

@@ -226,6 +226,7 @@ class TclCommandCopperClear(TclCommand):
                                                contour=contour,
                                                rest=rest,
                                                tools_storage=ncc_tools,
+                                               plot=False,
                                                run_threaded=False)
             return
 
@@ -259,6 +260,7 @@ class TclCommandCopperClear(TclCommand):
                                                    contour=contour,
                                                    rest=rest,
                                                    tools_storage=ncc_tools,
+                                                   plot=False,
                                                    run_threaded=False)
             return
         else:

+ 1 - 1
tclCommands/TclCommandCutout.py

@@ -123,7 +123,7 @@ class TclCommandCutout(TclCommand):
             geo_obj.solid_geometry = cascaded_union([LineString(segment) for segment in cuts])
 
         try:
-            self.app.new_object("geometry", name + "_cutout", geo_init_me)
+            self.app.new_object("geometry", name + "_cutout", geo_init_me, plot=False)
             self.app.inform.emit("[success] Rectangular-form Cutout operation finished.")
         except Exception as e:
             return "Operation failed: %s" % str(e)

+ 1 - 1
tclCommands/TclCommandDrillcncjob.py

@@ -181,4 +181,4 @@ class TclCommandDrillcncjob(TclCommandSignaled):
             job_obj.gcode_parse()
             job_obj.create_geometry()
 
-        self.app.new_object("cncjob", args['outname'], job_init)
+        self.app.new_object("cncjob", args['outname'], job_init, plot=False)

+ 1 - 1
tclCommands/TclCommandExteriors.py

@@ -61,4 +61,4 @@ class TclCommandExteriors(TclCommandSignaled):
             geo_obj.solid_geometry = obj_exteriors
 
         obj_exteriors = obj.get_exteriors()
-        self.app.new_object('geometry', outname, geo_init)
+        self.app.new_object('geometry', outname, geo_init, plot=False)

+ 2 - 2
tclCommands/TclCommandGeoCutout.py

@@ -279,7 +279,7 @@ class TclCommandGeoCutout(TclCommandSignaled):
                 app_obj.inform.emit("[success] Any-form Cutout operation finished.")
 
             outname = cutout_obj.options["name"] + "_cutout"
-            self.app.new_object('geometry', outname, geo_init)
+            self.app.new_object('geometry', outname, geo_init, plot=False)
 
             # cutout_obj.plot()
             # self.app.inform.emit("[success] Any-form Cutout operation finished.")
@@ -338,7 +338,7 @@ class TclCommandGeoCutout(TclCommandSignaled):
                 app_obj.inform.emit("[success] Any-form Cutout operation finished.")
 
             outname = cutout_obj.options["name"] + "_cutout"
-            self.app.new_object('geometry', outname, geo_init)
+            self.app.new_object('geometry', outname, geo_init, plot=False)
 
             cutout_obj = self.app.collection.get_by_name(outname)
         else:

+ 1 - 1
tclCommands/TclCommandImportSvg.py

@@ -71,7 +71,7 @@ class TclCommandImportSvg(TclCommandSignaled):
         with self.app.proc_container.new("Import SVG"):
 
             # Object creation
-            self.app.new_object(obj_type, outname, obj_init)
+            self.app.new_object(obj_type, outname, obj_init, plot=False)
 
             # Register recent file
             self.app.file_opened.emit("svg", filename)

+ 1 - 1
tclCommands/TclCommandIsolate.py

@@ -85,4 +85,4 @@ class TclCommandIsolate(TclCommandSignaled):
             self.raise_tcl_error('Expected FlatCAMGerber, got %s %s.' % (name, type(obj)))
 
         del args['name']
-        obj.isolate(**args)
+        obj.isolate(plot=False, **args)

+ 1 - 1
tclCommands/TclCommandJoinExcellon.py

@@ -61,4 +61,4 @@ class TclCommandJoinExcellon(TclCommand):
             FlatCAMExcellon.merge(objs, obj_)
 
         if objs is not None:
-            self.app.new_object("excellon", outname, initialize)
+            self.app.new_object("excellon", outname, initialize, plot=False)

+ 1 - 1
tclCommands/TclCommandJoinGeometry.py

@@ -61,4 +61,4 @@ class TclCommandJoinGeometry(TclCommand):
             FlatCAMGeometry.merge(objs, obj_)
 
         if objs is not None:
-            self.app.new_object("geometry", outname, initialize)
+            self.app.new_object("geometry", outname, initialize, plot=False)

+ 1 - 1
tclCommands/TclCommandMillDrills.py

@@ -128,7 +128,7 @@ class TclCommandMillDrills(TclCommandSignaled):
             del args['name']
 
             # This runs in the background... Is blocking handled?
-            success, msg = obj.generate_milling_drills(**args)
+            success, msg = obj.generate_milling_drills(plot=False, **args)
         except Exception as e:
             success = None
             msg = None

+ 1 - 1
tclCommands/TclCommandMillSlots.py

@@ -127,7 +127,7 @@ class TclCommandMillSlots(TclCommandSignaled):
             del args['name']
 
             # This runs in the background... Is blocking handled?
-            success, msg = obj.generate_milling_slots(**args)
+            success, msg = obj.generate_milling_slots(plot=False, **args)
 
         except Exception as e:
             success = None

+ 0 - 1
tclCommands/TclCommandMirror.py

@@ -103,6 +103,5 @@ class TclCommandMirror(TclCommandSignaled):
 
             try:
                 obj.mirror(axis, [dist, dist])
-                obj.plot()
             except Exception as e:
                 return "Operation failed: %s" % str(e)

+ 1 - 1
tclCommands/TclCommandNew.py

@@ -36,4 +36,4 @@ class TclCommandNew(TclCommand):
         :return: None or exception
         """
 
-        self.app.on_file_new()
+        self.app.on_file_new(cli=True)

+ 51 - 0
tclCommands/TclCommandNewExcellon.py

@@ -0,0 +1,51 @@
+from ObjectCollection import *
+from tclCommands.TclCommand import TclCommandSignaled
+
+
+class TclCommandNewExcellon(TclCommandSignaled):
+    """
+    Tcl shell command to subtract polygon from the given Geometry object.
+    """
+
+    # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
+    aliases = ['new_excellon']
+
+    # Dictionary of types from Tcl command, needs to be ordered.
+    # For positional arguments
+    arg_names = collections.OrderedDict([
+        ('name', str)
+    ])
+
+    # Dictionary of types from Tcl command, needs to be ordered.
+    # For options like -optionname value
+    option_types = collections.OrderedDict([
+
+    ])
+
+    # array of mandatory options for current Tcl command: required = {'name','outname'}
+    required = []
+
+    # structured help for current command, args needs to be ordered
+    help = {
+        'main': "Creates a new empty Excellon object.",
+        'args': collections.OrderedDict([
+            ('name', 'New object name.'),
+        ]),
+        'examples': []
+    }
+
+    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
+        """
+
+        if 'name' in args:
+            name = args['name']
+        else:
+            name = 'new_exc'
+        self.app.new_object('excellon', name, lambda x, y: None, plot=False)

+ 6 - 4
tclCommands/TclCommandNewGeometry.py

@@ -23,7 +23,7 @@ class TclCommandNewGeometry(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 = {
@@ -43,7 +43,9 @@ class TclCommandNewGeometry(TclCommandSignaled):
             without -somename and  we do not have them in known arg_names
         :return: None or exception
         """
+        if 'name' in args:
+            name = args['name']
+        else:
+            name = 'new_geo'
 
-        name = args['name']
-
-        self.app.new_object('geometry', str(name), lambda x, y: None)
+        self.app.new_object('geometry', str(name), lambda x, y: None, plot=False)

+ 68 - 0
tclCommands/TclCommandNewGerber.py

@@ -0,0 +1,68 @@
+from ObjectCollection import *
+from tclCommands.TclCommand import TclCommandSignaled
+
+
+class TclCommandNewGerber(TclCommandSignaled):
+    """
+    Tcl shell command to subtract polygon from the given Geometry object.
+    """
+
+    # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
+    aliases = ['new_gerber']
+
+    # Dictionary of types from Tcl command, needs to be ordered.
+    # For positional arguments
+    arg_names = collections.OrderedDict([
+        ('name', str)
+    ])
+
+    # Dictionary of types from Tcl command, needs to be ordered.
+    # For options like -optionname value
+    option_types = collections.OrderedDict([
+
+    ])
+
+    # array of mandatory options for current Tcl command: required = {'name','outname'}
+    required = []
+
+    # structured help for current command, args needs to be ordered
+    help = {
+        'main': "Creates a new empty Gerber object.",
+        'args': collections.OrderedDict([
+            ('name', 'New object name.'),
+        ]),
+        'examples': []
+    }
+
+    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
+        """
+
+        if 'name' in args:
+            name = args['name']
+        else:
+            name = 'new_grb'
+
+        def initialize(grb_obj, self):
+            grb_obj.multitool = False
+            grb_obj.source_file = []
+            grb_obj.multigeo = False
+            grb_obj.follow = False
+            grb_obj.apertures = {}
+            grb_obj.solid_geometry = []
+
+            try:
+                grb_obj.options['xmin'] = 0
+                grb_obj.options['ymin'] = 0
+                grb_obj.options['xmax'] = 0
+                grb_obj.options['ymax'] = 0
+            except KeyError:
+                pass
+
+        self.app.new_object('gerber', name, initialize, plot=False)

+ 1 - 1
tclCommands/TclCommandNregions.py

@@ -89,7 +89,7 @@ class TclCommandNregions(TclCommand):
                 non_copper = bounding_box.difference(geo)
                 geo_obj.solid_geometry = non_copper
 
-            self.app.new_object("geometry", args['outname'], geo_init)
+            self.app.new_object("geometry", args['outname'], geo_init, plot=False)
         except Exception as e:
             return "Operation failed: %s" % str(e)
 

+ 2 - 0
tclCommands/TclCommandOpenExcellon.py

@@ -46,5 +46,7 @@ class TclCommandOpenExcellon(TclCommandSignaled):
         """
 
         filename = args.pop('filename')
+        filename = filename.replace(' ', '')
 
+        args['plot'] = False
         self.app.open_excellon(filename, **args)

+ 4 - 1
tclCommands/TclCommandOpenGCode.py

@@ -45,5 +45,8 @@ class TclCommandOpenGCode(TclCommandSignaled):
             without -somename and  we do not have them in known arg_names
         :return: None or exception
         """
+        args['plot'] = False
+        filename = args["filename"]
+        filename = filename.replace(' ', '')
 
-        self.app.open_gcode(args['filename'], **args)
+        self.app.open_gcode(filename, **args)

+ 5 - 12
tclCommands/TclCommandOpenGerber.py

@@ -30,7 +30,7 @@ class TclCommandOpenGerber(TclCommandSignaled):
             ('filename', 'Path to file to open.'),
             ('outname', 'Name of the resulting Gerber object.')
         ]),
-        'examples': []
+        'examples': ["open_gerber gerber_object_path -outname bla"]
     }
 
     def execute(self, args, unnamed_args):
@@ -50,25 +50,19 @@ class TclCommandOpenGerber(TclCommandSignaled):
                 self.raise_tcl_error('Expected FlatCAMGerber, got %s %s.' % (outname, type(gerber_obj)))
 
             # Opening the file happens here
-            self.app.progress.emit(30)
             try:
                 gerber_obj.parse_file(filename)
-
             except IOError:
                 app_obj.inform.emit("[ERROR_NOTCL] Failed to open file: %s " % filename)
-                app_obj.progress.emit(0)
                 self.raise_tcl_error('Failed to open file: %s' % filename)
 
             except ParseError as e:
                 app_obj.inform.emit("[ERROR_NOTCL] Failed to parse file: %s, %s " % (filename, str(e)))
-                app_obj.progress.emit(0)
                 self.log.error(str(e))
                 return
 
-            # Further parsing
-            app_obj.progress.emit(70)
-
         filename = args['filename']
+        filename = filename.replace(' ', '')
 
         if 'outname' in args:
             outname = args['outname']
@@ -76,17 +70,16 @@ class TclCommandOpenGerber(TclCommandSignaled):
             outname = filename.split('/')[-1].split('\\')[-1]
 
         if 'follow' in args:
-            self.raise_tcl_error("The 'follow' parameter is obsolete. To create 'follow' geometry use the 'follow' parameter for the Tcl Command isolate()")
+            self.raise_tcl_error("The 'follow' parameter is obsolete. To create 'follow' geometry use the 'follow' "
+                                 "parameter for the Tcl Command isolate()")
 
         with self.app.proc_container.new("Opening Gerber"):
 
             # Object creation
-            self.app.new_object("gerber", outname, obj_init)
+            self.app.new_object("gerber", outname, obj_init, plot=False)
 
             # Register recent file
             self.app.file_opened.emit("gerber", filename)
 
-            self.app.progress.emit(100)
-
             # GUI feedback
             self.app.inform.emit("[success] Opened: " + filename)

+ 3 - 1
tclCommands/TclCommandOpenProject.py

@@ -43,5 +43,7 @@ class TclCommandOpenProject(TclCommandSignaled):
             without -somename and  we do not have them in known arg_names
         :return: None or exception
         """
+        filename = args['filename']
+        filename = filename.replace(' ', '')
 
-        self.app.open_project(args['filename'])
+        self.app.open_project(filename, cli=True, plot=False)

+ 9 - 3
tclCommands/TclCommandPaint.py

@@ -201,7 +201,9 @@ class TclCommandPaint(TclCommand):
                                                outname=outname,
                                                connect=connect,
                                                contour=contour,
-                                               tools_storage=paint_tools)
+                                               tools_storage=paint_tools,
+                                               plot=False,
+                                               run_threaded=False)
             return
 
         # Paint single polygon in the painted object
@@ -222,7 +224,9 @@ class TclCommandPaint(TclCommand):
                                                outname=outname,
                                                connect=connect,
                                                contour=contour,
-                                               tools_storage=paint_tools)
+                                               tools_storage=paint_tools,
+                                               plot=False,
+                                               run_threaded=False)
             return
 
         # Paint all polygons found within the box object from the the painted object
@@ -250,7 +254,9 @@ class TclCommandPaint(TclCommand):
                                                    outname=outname,
                                                    connect=connect,
                                                    contour=contour,
-                                                   tools_storage=paint_tools)
+                                                   tools_storage=paint_tools,
+                                                   plot=False,
+                                                   run_threaded=False)
             return
 
         else:

+ 3 - 3
tclCommands/TclCommandPanelize.py

@@ -90,7 +90,7 @@ class TclCommandPanelize(TclCommand):
         if 'threaded' in args:
             threaded = args['threaded']
         else:
-            threaded = 1
+            threaded = 0
 
         if 'spacing_columns' in args:
             spacing_columns = args['spacing_columns']
@@ -265,10 +265,10 @@ class TclCommandPanelize(TclCommand):
 
                 if isinstance(obj, FlatCAMExcellon):
                     self.app.progress.emit(50)
-                    self.app.new_object("excellon", outname, job_init_excellon, plot=True, autoselected=True)
+                    self.app.new_object("excellon", outname, job_init_excellon, plot=False, autoselected=True)
                 else:
                     self.app.progress.emit(50)
-                    self.app.new_object("geometry", outname, job_init_geometry, plot=True, autoselected=True)
+                    self.app.new_object("geometry", outname, job_init_geometry, plot=False, autoselected=True)
 
         if threaded == 1:
             proc = self.app.proc_container.new("Generating panel ... Please wait.")

+ 2 - 2
tclCommands/TclCommandPlot.py → tclCommands/TclCommandPlotAll.py

@@ -2,7 +2,7 @@ from ObjectCollection import *
 from tclCommands.TclCommand import TclCommand
 
 
-class TclCommandPlot(TclCommand):
+class TclCommandPlotAll(TclCommand):
     """
     Tcl shell command to update the plot on the user interface.
 
@@ -11,7 +11,7 @@ class TclCommandPlot(TclCommand):
     """
 
     # List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
-    aliases = ['plot']
+    aliases = ['plot_all']
 
     # Dictionary of types from Tcl command, needs to be ordered
     arg_names = collections.OrderedDict([

+ 51 - 0
tclCommands/TclCommandPlotObjects.py

@@ -0,0 +1,51 @@
+from ObjectCollection import *
+from tclCommands.TclCommand import TclCommand
+
+
+class TclCommandPlotObjects(TclCommand):
+    """
+    Tcl shell command to update the plot on the user interface.
+
+    example:
+        plot
+    """
+
+    # List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
+    aliases = ['plot_objects']
+
+    # Dictionary of types from Tcl command, needs to be ordered
+    arg_names = collections.OrderedDict([
+        ('names', str)
+    ])
+
+    # Dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
+    option_types = collections.OrderedDict([
+
+    ])
+
+    # array of mandatory options for current Tcl command: required = {'name','outname'}
+    required = []
+
+    # structured help for current command, args needs to be ordered
+    help = {
+        'main': "Plot a list of objects.",
+        'args': collections.OrderedDict([
+            ('names', "UA list of object names to be plotted.")
+        ]),
+        'examples': ["plot_objects"]
+    }
+
+    def execute(self, args, unnamed_args):
+        """
+
+        :param args:
+        :param unnamed_args:
+        :return:
+        """
+        names = [x.strip() for x in args['names'].split(",")]
+        objs = []
+        for name in names:
+            objs.append(self.app.collection.get_by_name(name))
+
+        for obj in objs:
+            obj.plot()

+ 4 - 1
tclCommands/__init__.py

@@ -35,7 +35,9 @@ import tclCommands.TclCommandMillSlots
 import tclCommands.TclCommandMirror
 import tclCommands.TclCommandNew
 import tclCommands.TclCommandNregions
+import tclCommands.TclCommandNewExcellon
 import tclCommands.TclCommandNewGeometry
+import tclCommands.TclCommandNewGerber
 import tclCommands.TclCommandOffset
 import tclCommands.TclCommandOpenExcellon
 import tclCommands.TclCommandOpenGCode
@@ -44,7 +46,8 @@ import tclCommands.TclCommandOpenProject
 import tclCommands.TclCommandOptions
 import tclCommands.TclCommandPaint
 import tclCommands.TclCommandPanelize
-import tclCommands.TclCommandPlot
+import tclCommands.TclCommandPlotAll
+import tclCommands.TclCommandPlotObjects
 import tclCommands.TclCommandSaveProject
 import tclCommands.TclCommandSaveSys
 import tclCommands.TclCommandScale