Преглед изворни кода

- fixed the Tcl Command Delete to have an argument -f that will force deletion evading the popup (if the popup is enabled). The sme command without a name now will delete all objects
- fixed the Tcl Command JoinExcellons
- fixed the Tcl Command JoinGeometry
- fixed the Tcl Command Mirror
- updated the Tcl Command Mirror to use a (X,Y) origin parameter. Works if the -box parameter is not used.
- updated the Tcl Command Offset. Now it can use only -x or -y parameter no longer is mandatory to have both. The one that is not present will be assumed 0.0
- updated the Tcl Command Panelize. The -rows and -columns parameters are no longer both required. If one is not present then it is assumed to be zero.
- updated the Tcl Command Scale. THe -origin parameter can now be a tuple of (x,y) coordinates.
- updated the Tcl Command Skew. Now it can use only -x or -y parameter no longer is mandatory to have both. The one that is not present will be assumed 0.0
- updated the help for all the Tcl Commands

Marius Stanciu пре 5 година
родитељ
комит
42949021b1
53 измењених фајлова са 322 додато и 178 уклоњено
  1. 16 7
      FlatCAMApp.py
  2. 13 0
      README.md
  3. 1 1
      tclCommands/TclCommandAddCircle.py
  4. 1 1
      tclCommands/TclCommandAddRectangle.py
  5. 1 1
      tclCommands/TclCommandAlignDrill.py
  6. 1 1
      tclCommands/TclCommandAlignDrillGrid.py
  7. 1 1
      tclCommands/TclCommandBbox.py
  8. 1 0
      tclCommands/TclCommandBounds.py
  9. 1 1
      tclCommands/TclCommandClearShell.py
  10. 1 1
      tclCommands/TclCommandCutout.py
  11. 39 13
      tclCommands/TclCommandDelete.py
  12. 2 2
      tclCommands/TclCommandExportGcode.py
  13. 1 1
      tclCommands/TclCommandExportGerber.py
  14. 1 1
      tclCommands/TclCommandExportSVG.py
  15. 2 2
      tclCommands/TclCommandExteriors.py
  16. 2 2
      tclCommands/TclCommandFollow.py
  17. 2 2
      tclCommands/TclCommandGeoCutout.py
  18. 3 3
      tclCommands/TclCommandGeoUnion.py
  19. 2 2
      tclCommands/TclCommandGetNames.py
  20. 2 2
      tclCommands/TclCommandGetSys.py
  21. 2 2
      tclCommands/TclCommandImportSvg.py
  22. 3 3
      tclCommands/TclCommandInteriors.py
  23. 8 4
      tclCommands/TclCommandIsolate.py
  24. 11 10
      tclCommands/TclCommandJoinExcellon.py
  25. 10 8
      tclCommands/TclCommandJoinGeometry.py
  26. 1 1
      tclCommands/TclCommandListSys.py
  27. 9 7
      tclCommands/TclCommandMillDrills.py
  28. 9 5
      tclCommands/TclCommandMillSlots.py
  29. 26 17
      tclCommands/TclCommandMirror.py
  30. 1 1
      tclCommands/TclCommandNew.py
  31. 1 1
      tclCommands/TclCommandNewExcellon.py
  32. 3 2
      tclCommands/TclCommandNewGeometry.py
  33. 1 1
      tclCommands/TclCommandNewGerber.py
  34. 2 2
      tclCommands/TclCommandNregions.py
  35. 15 8
      tclCommands/TclCommandOffset.py
  36. 8 2
      tclCommands/TclCommandOpenExcellon.py
  37. 7 3
      tclCommands/TclCommandOpenGCode.py
  38. 8 3
      tclCommands/TclCommandOpenGerber.py
  39. 7 3
      tclCommands/TclCommandOpenProject.py
  40. 3 3
      tclCommands/TclCommandOptions.py
  41. 21 7
      tclCommands/TclCommandPanelize.py
  42. 1 1
      tclCommands/TclCommandPlotAll.py
  43. 4 4
      tclCommands/TclCommandPlotObjects.py
  44. 5 2
      tclCommands/TclCommandSaveProject.py
  45. 2 2
      tclCommands/TclCommandSaveSys.py
  46. 21 8
      tclCommands/TclCommandScale.py
  47. 2 2
      tclCommands/TclCommandSetActive.py
  48. 5 3
      tclCommands/TclCommandSetOrigin.py
  49. 2 2
      tclCommands/TclCommandSetSys.py
  50. 21 10
      tclCommands/TclCommandSkew.py
  51. 5 3
      tclCommands/TclCommandSubtractPoly.py
  52. 3 2
      tclCommands/TclCommandSubtractRectangle.py
  53. 2 2
      tclCommands/TclCommandWriteGCode.py

+ 16 - 7
FlatCAMApp.py

@@ -1033,7 +1033,7 @@ class App(QtCore.QObject):
                                           'Toolchange_manual, Users, all, angle_x, angle_y, axis, auto, axisoffset, '
                                           'box, center_x, center_y, columns, combine, connect, contour, default, '
                                           'depthperpass, dia, diatol, dist, drilled_dias, drillz, dwelltime, '
-                                          'extracut_length, '
+                                          'extracut_length, f, '
                                           'feedrate_z, grbl_11, GRBL_laser, gridoffsety, gridx, gridy, has_offset, '
                                           'holes, hpgl, iso_type, line_xyz, margin, marlin, method, milled_dias, '
                                           'minoffset, name, offset, opt_type, order, outname, overlap, '
@@ -2305,7 +2305,8 @@ class App(QtCore.QObject):
         # #####################################################################################
         self.tcl_commands_list = ['add_circle', 'add_poly', 'add_polygon', 'add_polyline', 'add_rectangle',
                                   'aligndrill', 'aligndrillgrid', 'bbox', 'bounding_box', 'clear', 'cncjob', 'cutout',
-                                  'delete', 'drillcncjob', 'export_dxf', 'edxf', 'export_excellon', 'ee', 'export_exc',
+                                  'del', 'delete', 'drillcncjob', 'export_dxf', 'edxf', 'export_excellon', 'ee',
+                                  'export_exc',
                                   'export_gcode', 'export_gerber', 'egr', 'export_svg', 'ext', 'exteriors', 'follow',
                                   'geo_union', 'geocutout', 'get_names', 'get_sys', 'getsys', 'help', 'import_svg',
                                   'interiors', 'isolate', 'join_excellon', 'join_excellons', 'join_geometries',
@@ -2326,7 +2327,7 @@ class App(QtCore.QObject):
                                  'axisoffset',
                                  'box', 'center_x', 'center_y', 'columns', 'combine', 'connect', 'contour', 'default',
                                  'depthperpass', 'dia', 'diatol', 'dist', 'drilled_dias', 'drillz',
-                                 'dwelltime', 'extracut_length',
+                                 'dwelltime', 'extracut_length', 'f',
                                  'feedrate_z', 'grbl_11', 'GRBL_laser', 'gridoffsety', 'gridx', 'gridy',
                                  'has_offset', 'holes', 'hpgl', 'iso_type', 'line_xyz', 'margin', 'marlin', 'method',
                                  'milled_dias', 'minoffset', 'name', 'offset', 'opt_type', 'order',
@@ -7201,10 +7202,11 @@ class App(QtCore.QObject):
     # Hovering over Selected tab, if the selected tab is a Geometry it will delete tools in tool table. But even if
     # there is a Selected tab in focus with a Geometry inside, if you hover over canvas it will delete an object.
     # Complicated, I know :)
-    def on_delete(self):
+    def on_delete(self, force_deletion=False):
         """
         Delete the currently selected FlatCAMObjs.
 
+        :param force_deletion:  used by Tcl command
         :return: None
         """
         self.report_usage("on_delete()")
@@ -7216,7 +7218,7 @@ class App(QtCore.QObject):
         # a geometry object before we update it.
         if self.geo_editor.editor_active is False and self.exc_editor.editor_active is False \
                 and self.grb_editor.editor_active is False:
-            if self.defaults["global_delete_confirmation"] is True:
+            if self.defaults["global_delete_confirmation"] is True and force_deletion is False:
                 msgbox = QtWidgets.QMessageBox()
                 msgbox.setWindowTitle(_("Delete objects"))
                 msgbox.setWindowIcon(QtGui.QIcon(self.resource_location + '/deleteshape32.png'))
@@ -7230,7 +7232,10 @@ class App(QtCore.QObject):
                 msgbox.exec_()
                 response = msgbox.clickedButton()
 
-            if response == bt_ok or self.defaults["global_delete_confirmation"] is False:
+            if self.defaults["global_delete_confirmation"] is False or force_deletion is True:
+                response = bt_ok
+
+            if response == bt_ok:
                 if self.collection.get_active():
                     self.log.debug("App.on_delete()")
 
@@ -9539,6 +9544,7 @@ class App(QtCore.QObject):
         File menu callback for opening a Gerber.
 
         :param signal: required because clicking the entry will generate a checked signal which needs a container
+        :param name:
         :return: None
         """
 
@@ -9585,6 +9591,7 @@ class App(QtCore.QObject):
         File menu callback for opening an Excellon file.
 
         :param signal: required because clicking the entry will generate a checked signal which needs a container
+        :param name:
         :return: None
         """
 
@@ -9619,10 +9626,12 @@ class App(QtCore.QObject):
 
     def on_fileopengcode(self, signal: bool = None, name=None):
         """
+
         File menu call back for opening gcode.
 
         :param signal: required because clicking the entry will generate a checked signal which needs a container
-        :return: None
+        :param name:
+        :return:
         """
 
         self.report_usage("on_fileopengcode")

+ 13 - 0
README.md

@@ -9,6 +9,19 @@ CAD program, and create G-Code for Isolation routing.
 
 =================================================
 
+9.4.2020 
+
+- fixed the Tcl Command Delete to have an argument -f that will force deletion evading the popup (if the popup is enabled). The sme command without a name now will delete all objects
+- fixed the Tcl Command JoinExcellons
+- fixed the Tcl Command JoinGeometry
+- fixed the Tcl Command Mirror
+- updated the Tcl Command Mirror to use a (X,Y) origin parameter. Works if the -box parameter is not used.
+- updated the Tcl Command Offset. Now it can use only -x or -y parameter no longer is mandatory to have both. The one that is not present will be assumed 0.0
+- updated the Tcl Command Panelize. The -rows and -columns parameters are no longer both required. If one is not present then it is assumed to be zero.
+- updated the Tcl Command Scale. THe -origin parameter can now be a tuple of (x,y) coordinates.
+- updated the Tcl Command Skew. Now it can use only -x or -y parameter no longer is mandatory to have both. The one that is not present will be assumed 0.0
+- updated the help for all the Tcl Commands
+
 6.04.2020 
 
 - added key shortcuts (arrow up/down) that will select the objects in the Project tab if the focus is in that tab

+ 1 - 1
tclCommands/TclCommandAddCircle.py

@@ -38,7 +38,7 @@ class TclCommandAddCircle(TclCommand):
             ('center_y', 'Y coordinates of the center of the circle.'),
             ('radius', 'Radius of the circle.')
         ]),
-        'examples': []
+        'examples': ['add_circle geo_name 1.0 2.0 3']
     }
 
     def execute(self, args, unnamed_args):

+ 1 - 1
tclCommands/TclCommandAddRectangle.py

@@ -37,7 +37,7 @@ class TclCommandAddRectangle(TclCommandSignaled):
             ('x0 y0', 'Bottom left corner coordinates.'),
             ('x1 y1', 'Top right corner coordinates.')
         ]),
-        'examples': []
+        'examples': ["add_rectangle geo_name 0 0 10 10"]
     }
 
     def execute(self, args, unnamed_args):

+ 1 - 1
tclCommands/TclCommandAlignDrill.py

@@ -41,7 +41,7 @@ class TclCommandAlignDrill(TclCommandSignaled):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Create excellon with drills for aligment.",
+        'main': "Create an Excellon object with drills for alignment.",
         'args': collections.OrderedDict([
             ('name', 'Name of the object (Gerber or Excellon) to mirror.'),
             ('dia', 'Tool diameter'),

+ 1 - 1
tclCommands/TclCommandAlignDrillGrid.py

@@ -39,7 +39,7 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Create excellon with drills for aligment grid.",
+        'main': "Create an Excellon object with drills for alignment arranged in a grid.",
         'args': collections.OrderedDict([
             ('outname', 'Name of the object to create.'),
             ('dia', 'Tool diameter.'),

+ 1 - 1
tclCommands/TclCommandBbox.py

@@ -38,7 +38,7 @@ class TclCommandBbox(TclCommand):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Creates a Geometry object that surrounds the object.",
+        'main': "Creates a rectangular Geometry object that surrounds the object.",
         'args': collections.OrderedDict([
             ('name', 'Object name for which to create bounding box. String'),
             ('outname', 'Name of the resulting Geometry object. String.'),

+ 1 - 0
tclCommands/TclCommandBounds.py

@@ -12,6 +12,7 @@ if '_' not in builtins.__dict__:
 
 log = logging.getLogger('base')
 
+
 class TclCommandBounds(TclCommand):
     """
     Tcl shell command to return the bounds values for a supplied list of objects (identified by their names).

+ 1 - 1
tclCommands/TclCommandClearShell.py

@@ -38,7 +38,7 @@ class TclCommandClearShell(TclCommand):
         'main': "Clear the text in the Tcl Shell browser.",
         'args': collections.OrderedDict([
         ]),
-        'examples': []
+        'examples': ['clear']
     }
 
     def execute(self, args, unnamed_args):

+ 1 - 1
tclCommands/TclCommandCutout.py

@@ -48,7 +48,7 @@ class TclCommandCutout(TclCommand):
             ('gapsize', 'Size of gap. Default = 0.1'),
             ('gaps', "Type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right and '4' = one each side. Default = 4"),
         ]),
-        'examples': []
+        'examples': ['cutout new_geo -dia 1.2 -margin 0.1 -gapsize 1 -gaps "tb" ']
     }
 
     def execute(self, args, unnamed_args):

+ 39 - 13
tclCommands/TclCommandDelete.py

@@ -12,7 +12,7 @@ class TclCommandDelete(TclCommand):
     """
 
     # List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
-    aliases = ['delete']
+    aliases = ['delete', 'del']
 
     # Dictionary of types from Tcl command, needs to be ordered
     arg_names = collections.OrderedDict([
@@ -21,19 +21,23 @@ class TclCommandDelete(TclCommand):
 
     # Dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
     option_types = collections.OrderedDict([
-
+        ('f', bool)
     ])
 
     # 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 = {
-        'main': 'Deletes the given object.',
+        'main': 'Deletes the given object. If no name is given will delete all objects.',
         'args': collections.OrderedDict([
             ('name', 'Name of the Object.'),
+            ('f', 'Use this parameter to force deletion.')
         ]),
-        'examples': []
+        'examples': ['del new_geo -f True\n'
+                     'delete new_geo -f 1\n'
+                     'del new_geo -f\n'
+                     'del new_geo']
     }
 
     def execute(self, args, unnamed_args):
@@ -43,13 +47,35 @@ class TclCommandDelete(TclCommand):
         :param unnamed_args:
         :return:
         """
-
-        obj_name = args['name']
+        obj_name = None
 
         try:
-            # deselect all  to avoid delete selected object when run  delete  from  shell
-            self.app.collection.set_all_inactive()
-            self.app.collection.set_active(str(obj_name))
-            self.app.on_delete()  # Todo: This is an event handler for the GUI... bad?
-        except Exception as e:
-            return "Command failed: %s" % str(e)
+            obj_name = args['name']
+            delete_all = False
+        except KeyError:
+            delete_all = True
+
+        is_forced = False
+        if 'f' in args:
+            try:
+                if args['f'] is None:
+                    is_forced = True
+                else:
+                    is_forced = True if eval(str(args['f'])) else False
+            except KeyError:
+                is_forced = True
+
+        if delete_all is False:
+            try:
+                # deselect all  to avoid delete selected object when run  delete  from  shell
+                self.app.collection.set_all_inactive()
+                self.app.collection.set_active(str(obj_name))
+                self.app.on_delete(force_deletion=is_forced)
+            except Exception as e:
+                return "Command failed: %s" % str(e)
+        else:
+            try:
+                self.app.collection.set_all_active()
+                self.app.on_delete(force_deletion=is_forced)
+            except Exception as e:
+                return "Command failed: %s" % str(e)

+ 2 - 2
tclCommands/TclCommandExportGcode.py

@@ -48,11 +48,11 @@ class TclCommandExportGcode(TclCommandSignaled):
     help = {
         'main': "Export gcode into console output.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the source Geometry object.'),
+            ('name', 'Name of the source Geometry object. Required.'),
             ('preamble', 'Prepend GCODE.'),
             ('postamble', 'Append GCODE.')
         ]),
-        'examples': []
+        'examples': ['export_gcode geo_name -preamble "G01 X10 Y10" -postamble "G00 X20 Y20\nM04"']
     }
 
     def execute(self, args, unnamed_args):

+ 1 - 1
tclCommands/TclCommandExportGerber.py

@@ -31,7 +31,7 @@ class TclCommandExportGerber(TclCommand):
     help = {
         'main': "Export a Gerber Object as a Gerber File.",
         'args': collections.OrderedDict([
-            ('obj_name', 'Name of the object to export.'),
+            ('obj_name', 'Name of the object to export. Required.'),
             ('filename', 'Path to the file to export.')
         ]),
         'examples': ['export_gerber my_gerber path/my_file.gbr']

+ 1 - 1
tclCommands/TclCommandExportSVG.py

@@ -33,7 +33,7 @@ class TclCommandExportSVG(TclCommand):
     help = {
         'main': "Export a Geometry Object as a SVG File.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the object export.'),
+            ('name', 'Name of the object export. Required.'),
             ('filename', 'Path to the file to export.'),
             ('scale_factor', 'Multiplication factor used for scaling line widths during export.')
         ]),

+ 2 - 2
tclCommands/TclCommandExteriors.py

@@ -29,10 +29,10 @@ class TclCommandExteriors(TclCommandSignaled):
     help = {
         'main': "Get exteriors of polygons.",
         'args':  collections.OrderedDict([
-            ('name', 'Name of the source Geometry object.'),
+            ('name', 'Name of the source Geometry object. Required.'),
             ('outname', 'Name of the resulting Geometry object.')
         ]),
-        'examples': []
+        'examples': ['ext geo_source_name -outname "final_geo"']
     }
 
     def execute(self, args, unnamed_args):

+ 2 - 2
tclCommands/TclCommandFollow.py

@@ -29,10 +29,10 @@ class TclCommandFollow(TclCommandSignaled):
     help = {
         'main': "Creates a geometry object following gerber paths.",
         'args': collections.OrderedDict([
-            ('name', 'Object name to follow.'),
+            ('name', 'Object name to follow. Required.'),
             ('outname', 'Name of the resulting Geometry object.')
         ]),
-        'examples': ['follow name -outname name_follow']
+        'examples': ['follow name -outname "name_follow"']
     }
 
     def execute(self, args, unnamed_args):

+ 2 - 2
tclCommands/TclCommandGeoCutout.py

@@ -45,14 +45,14 @@ class TclCommandGeoCutout(TclCommandSignaled):
     help = {
         'main': 'Creates board cutout from an object (Gerber or Geometry) of any shape',
         'args': collections.OrderedDict([
-            ('name', 'Name of the object.'),
+            ('name', 'Name of the object to be cutout. Required'),
             ('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': ["      #isolate margin for example from fritzing arduino shield or any svg etc\n" +
+        '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" +

+ 3 - 3
tclCommands/TclCommandGeoUnion.py

@@ -32,12 +32,12 @@ class TclCommandGeoUnion(TclCommand):
     help = {
         'main': ('Runs a union operation (addition) on the components '
                  'of the geometry object. For example, if it contains '
-                 '2 intersecting polygons, this opperation adds them into'
+                 '2 intersecting polygons, this operation adds them into'
                  'a single larger polygon.'),
         'args': collections.OrderedDict([
-            ('name', 'Name of the Geometry Object.'),
+            ('name', 'Name of the Geometry Object that contain the components to be joined. Required.'),
         ]),
-        'examples': []
+        'examples': ['geo_union target_geo']
     }
 
     def execute(self, args, unnamed_args):

+ 2 - 2
tclCommands/TclCommandGetNames.py

@@ -29,11 +29,11 @@ class TclCommandGetNames(TclCommand):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': 'Lists the names of objects in the project.',
+        'main': 'Lists the names of objects in the project. It returns a string with names separated by \n',
         'args': collections.OrderedDict([
 
         ]),
-        'examples': []
+        'examples': ['get_names']
     }
 
     def execute(self, args, unnamed_args):

+ 2 - 2
tclCommands/TclCommandGetSys.py

@@ -36,9 +36,9 @@ class TclCommandGetSys(TclCommand):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Returns the value of the system variable.",
+        'main': "Returns the value of the targeted system variable.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the system variable.'),
+            ('name', 'Name of the system variable. Required.'),
         ]),
         'examples': ['get_sys excellon_zeros']
     }

+ 2 - 2
tclCommands/TclCommandImportSvg.py

@@ -30,11 +30,11 @@ class TclCommandImportSvg(TclCommandSignaled):
     help = {
         'main': "Import an SVG file as a Geometry Object..",
         'args':  collections.OrderedDict([
-            ('filename', 'Path to file to open.'),
+            ('filename', 'Absolute path to file to open. Required.'),
             ('type', 'Import as gerber or geometry(default).'),
             ('outname', 'Name of the resulting Geometry object.')
         ]),
-        'examples': []
+        'examples': ['import_svg D:\\my_beautiful_svg_file.SVG']
     }
 
     def execute(self, args, unnamed_args):

+ 3 - 3
tclCommands/TclCommandInteriors.py

@@ -27,12 +27,12 @@ class TclCommandInteriors(TclCommandSignaled):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Get interiors of polygons.",
+        'main': "Return the interiors of polygons as a list of Shapely geometry elements.",
         'args':  collections.OrderedDict([
-            ('name', 'Name of the source Geometry object.'),
+            ('name', 'Name of the source Geometry object. Required.'),
             ('outname', 'Name of the resulting Geometry object.')
         ]),
-        'examples': []
+        'examples': ['interiors my_geo_name -outname "outputed_geo"']
     }
 
     def execute(self, args, unnamed_args):

+ 8 - 4
tclCommands/TclCommandIsolate.py

@@ -29,7 +29,7 @@ class TclCommandIsolate(TclCommandSignaled):
         ('dia', float),
         ('passes', int),
         ('overlap', float),
-        ('combine', int),
+        ('combine', bool),
         ('outname', str),
         ('follow', str),
         ('iso_type', int)
@@ -43,18 +43,18 @@ class TclCommandIsolate(TclCommandSignaled):
     help = {
         'main': "Creates isolation routing geometry for the given Gerber.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the source object.'),
+            ('name', 'Name of the source object. Required.'),
             ('dia', 'Tool diameter.'),
             ('passes', 'Passes of tool width.'),
             ('overlap', 'Percentage of tool diameter to overlap current pass over previous pass. Float [0, 99.9999]\n'
                         'E.g: for a 25% from tool diameter overlap use -overlap 25'),
-            ('combine', 'Combine all passes into one geometry.'),
+            ('combine', 'Combine all passes into one geometry. Can be True or False, 1 or 0'),
             ('outname', 'Name of the resulting Geometry object.'),
             ('follow', 'Create a Geometry that follows the Gerber path.'),
             ('iso_type', 'A value of 0 will isolate exteriors, a value of 1 will isolate interiors '
                          'and a value of 2 will do full isolation.')
         ]),
-        'examples': []
+        'examples': ['isolate my_geo -dia 0.1 -passes 2 -overlap 10 -combine True -iso_type 2 -outname out_geo']
     }
 
     def execute(self, args, unnamed_args):
@@ -80,6 +80,10 @@ class TclCommandIsolate(TclCommandSignaled):
         if 'follow' not in args:
             args['follow'] = None
 
+        # evaluate this parameter so True, False, 0 and 1 works
+        if "combine" in args:
+            args['combine'] = eval(args['combine'])
+
         obj = self.app.collection.get_by_name(name)
         if obj is None:
             self.raise_tcl_error("Object not found: %s" % name)

+ 11 - 10
tclCommands/TclCommandJoinExcellon.py

@@ -22,7 +22,6 @@ class TclCommandJoinExcellon(TclCommand):
 
     # 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'}
@@ -30,14 +29,14 @@ class TclCommandJoinExcellon(TclCommand):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Runs a merge operation (join) on the Excellon objects.",
+        'main': "Runs a merge operation (join) on the Excellon objects.\n"
+                "The names of the Excellon objects to be merged will be entered after the outname,\n"
+                "separated by spaces. See the example bellow.\n"
+                "WARNING: if the name of an Excellon objects has spaces, enclose the name with quotes.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the new Excellon Object.'),
-            ('obj_name_0', 'Name of the first object'),
-            ('obj_name_1', 'Name of the second object.'),
-            ('obj_name_2...', 'Additional object names')
+            ('outname', 'Name of the new Excellon Object made by joining of other Excellon objects. Required'),
         ]),
-        'examples': []
+        'examples': ['join_excellons merged_new_excellon exc_name_1 "exc name_2"']
     }
 
     def execute(self, args, unnamed_args):
@@ -48,7 +47,7 @@ class TclCommandJoinExcellon(TclCommand):
         :return:
         """
 
-        outname = args['name']
+        outname = args['outname']
         obj_names = unnamed_args
 
         objs = []
@@ -60,7 +59,9 @@ class TclCommandJoinExcellon(TclCommand):
                 objs.append(obj)
 
         def initialize(obj_, app):
-            FlatCAMExcellon.merge(objs, obj_)
+            FlatCAMExcellon.merge(self, objs, obj_)
 
-        if objs is not None:
+        if objs:
             self.app.new_object("excellon", outname, initialize, plot=False)
+        else:
+            return "No Excellon objects to be joined."

+ 10 - 8
tclCommands/TclCommandJoinGeometry.py

@@ -30,14 +30,14 @@ class TclCommandJoinGeometry(TclCommand):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Runs a merge operation (join) on the Excellon objects.",
+        'main': "Runs a merge operation (join) on the Geometry objects.\n"
+                "The names of the Geometry objects to be merged will be entered after the outname,\n"
+                "separated by spaces. See the example bellow.\n"
+                "WARNING: if the name of an Geometry objects has spaces, enclose the name with quotes.",
         'args': collections.OrderedDict([
-            ('outname', 'Name of the new Geometry Object.'),
-            ('obj_name_0', 'Name of the first object'),
-            ('obj_name_1', 'Name of the second object.'),
-            ('obj_name_2...', 'Additional object names')
+            ('outname', 'Name of the new Geometry Object made by joining of other Geometry objects. Required'),
         ]),
-        'examples': []
+        'examples': ['join_geometry merged_new_geo geo_name_1 "geo name_2"']
     }
 
     def execute(self, args, unnamed_args):
@@ -60,7 +60,9 @@ class TclCommandJoinGeometry(TclCommand):
                 objs.append(obj)
 
         def initialize(obj_, app):
-            FlatCAMGeometry.merge(objs, obj_)
+            FlatCAMGeometry.merge(self, objs, obj_)
 
-        if objs is not None:
+        if objs:
             self.app.new_object("geometry", outname, initialize, plot=False)
+        else:
+            return "No Geometry objects to be joined."

+ 1 - 1
tclCommands/TclCommandListSys.py

@@ -40,7 +40,7 @@ class TclCommandListSys(TclCommand):
                 "of the system variable.\n"
                 "In that case it will list only the system variables that starts with that string.\n"
                 "Main categories start with: gerber or excellon or geometry or cncjob or global.\n"
-                "Note: Use get_sys TclCommand to get the value and set_sys TclCommand to set it.\n",
+                "Note: Use 'get_sys system variable' to get the value and 'set_sys system variable value' to set it.\n",
         'args': collections.OrderedDict([
         ]),
         'examples': ['list_sys',

+ 9 - 7
tclCommands/TclCommandMillDrills.py

@@ -34,7 +34,7 @@ class TclCommandMillDrills(TclCommandSignaled):
         ('milled_dias', str),
         ('outname', str),
         ('tooldia', float),
-        ('use_threads', bool),
+        ('use_thread', bool),
         ('diatol', float)
     ])
 
@@ -45,10 +45,13 @@ class TclCommandMillDrills(TclCommandSignaled):
     help = {
         'main': "Create Geometry Object for milling drill holes from Excellon.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the Excellon Object.'),
-            ('milled_dias', 'Comma separated tool diameters of the drills to be milled (example: 0.6, 1.0 or 3.125).'),
+            ('name', 'Name of the Excellon Object. Required.'),
+            ('milled_dias', 'Comma separated tool diameters of the drills to be milled (example: 0.6, 1.0 or 3.125).\n'
+                            'Exception: if you enter "all" then the drills for all tools will be milled.\n'
+                            'WARNING: no spaces are allowed in the list of tools.\n'
+                            'As a precaution you can enclose them with quotes.'),
             ('tooldia', 'Diameter of the milling tool (example: 0.1).'),
-            ('outname', 'Name of object to create.'),
+            ('outname', 'Name of object to be created holding the milled geometries.'),
             ('use_thread', 'If to use multithreading: True or False.'),
             ('diatol', 'Tolerance. Percentange (0.0 ... 100.0) within which dias in milled_dias will be judged to be '
                        'the same as the ones in the tools from the Excellon object. E.g: if in milled_dias we have a '
@@ -56,7 +59,8 @@ class TclCommandMillDrills(TclCommandSignaled):
                        'diatol = 5.0 then the drills with the dia = (0.95 ... 1.05) '
                        'in Excellon will be processed. Float number.')
         ]),
-        'examples': ['milldrills mydrills', 'milld my_excellon.drl']
+        'examples': ['milldrills mydrills -milled_dias "0.6,0.8" -tooldia 0.1 -diatol 10 -outname milled_holes',
+                     'milld my_excellon.drl']
     }
 
     def execute(self, args, unnamed_args):
@@ -85,8 +89,6 @@ class TclCommandMillDrills(TclCommandSignaled):
         if not obj.drills:
             self.raise_tcl_error("The Excellon object has no drills: %s" % name)
 
-        units = self.app.defaults['units'].upper()
-
         try:
             if 'milled_dias' in args and args['milled_dias'] != 'all':
                 diameters = [x.strip() for x in args['milled_dias'].split(",") if x != '']

+ 9 - 5
tclCommands/TclCommandMillSlots.py

@@ -34,7 +34,7 @@ class TclCommandMillSlots(TclCommandSignaled):
         ('milled_dias', str),
         ('outname', str),
         ('tooldia', float),
-        ('use_threads', bool),
+        ('use_thread', bool),
         ('diatol', float)
     ])
 
@@ -45,10 +45,13 @@ class TclCommandMillSlots(TclCommandSignaled):
     help = {
         'main': "Create Geometry Object for milling slot holes from Excellon.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the Excellon Object.'),
-            ('milled_dias', 'Comma separated tool diameters of the slots to be milled (example: 0.6, 1.0 or 3.125).'),
+            ('name', 'Name of the Excellon Object. Required.'),
+            ('milled_dias', 'Comma separated tool diameters of the slots to be milled (example: 0.6, 1.0 or 3.125).\n'
+                            'Exception: if you enter "all" then the slots for all tools will be milled.\n'
+                            'WARNING: no spaces are allowed in the list of tools.\n'
+                            'As a precaution you can enclose them with quotes.'),
             ('tooldia', 'Diameter of the milling tool (example: 0.1).'),
-            ('outname', 'Name of object to create.'),
+            ('outname', 'Name of object to be created holding the milled geometries.'),
             ('use_thread', 'If to use multithreading: True or False.'),
             ('diatol', 'Tolerance. Percentange (0.0 ... 100.0) within which dias in milled_dias will be judged to be '
                        'the same as the ones in the tools from the Excellon object. E.g: if in milled_dias we have a '
@@ -56,7 +59,8 @@ class TclCommandMillSlots(TclCommandSignaled):
                        'diatol = 5.0 then the slots with the dia = (0.95 ... 1.05) '
                        'in Excellon will be processed. Float number.')
         ]),
-        'examples': ['millslots mydrills', 'mills my_excellon.drl']
+        'examples': ['millslots myslots -milled_dias "0.6,0.8" -tooldia 0.1 -diatol 10 -outname milled_slots',
+                     'mills my_excellon.drl']
     }
 
     def execute(self, args, unnamed_args):

+ 26 - 17
tclCommands/TclCommandMirror.py

@@ -24,22 +24,25 @@ class TclCommandMirror(TclCommandSignaled):
     option_types = collections.OrderedDict([
         ('axis', str),
         ('box', str),
-        ('dist', float)
+        ('origin', str)
     ])
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
-    required = ['name', 'axis']
+    required = ['name']
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Opens an Excellon file.",
+        'main': "Will mirror an named object.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the object (Gerber or Excellon) to mirror.'),
-            ('box', 'Name of object which act as box (cutout for example.)'),
+            ('name', 'Name of the object (Gerber, Geometry or Excellon) to be mirrored. Required.'),
             ('axis', 'Mirror axis parallel to the X or Y axis.'),
-            ('dist', 'Distance of the mirror axis to the X or Y axis.')
+            ('box', 'Name of object which act as box (cutout for example.)'),
+            ('origin', 'Reference point . It is used only if the box is not used. Format (x,y).\n'
+                       'Comma will separate the X and Y coordinates.\n'
+                       'WARNING: no spaces are allowed. If uncertain enclose the two values inside parenthesis.\n'
+                       'See the example.')
         ]),
-        'examples': []
+        'examples': ['mirror obj_name -box box_geo -axis X -origin 3.2,4.7']
     }
 
     def execute(self, args, unnamed_args):
@@ -69,10 +72,13 @@ class TclCommandMirror(TclCommandSignaled):
             return "ERROR: Only Gerber, Excellon and Geometry objects can be mirrored."
 
         # Axis
-        try:
-            axis = args['axis'].upper()
-        except KeyError:
-            return "ERROR: Specify -axis X or -axis Y"
+        if 'axis' in args:
+            try:
+                axis = args['axis'].upper()
+            except KeyError:
+                axis = 'Y'
+        else:
+            axis = 'Y'
 
         # Box
         if 'box' in args:
@@ -91,19 +97,22 @@ class TclCommandMirror(TclCommandSignaled):
 
                 obj.mirror(axis, [px, py])
                 obj.plot()
-
+                return
             except Exception as e:
                 return "Operation failed: %s" % str(e)
 
-        else:
+        # Origin
+        if 'origin' in args:
             try:
-                dist = float(args['dist'])
+                origin_val = eval(args['origin'])
+                x = float(origin_val[0])
+                y = float(origin_val[1])
             except KeyError:
-                dist = 0.0
+                x, y = (0, 0)
             except ValueError:
-                return "Invalid distance: %s" % args['dist']
+                return "Invalid distance: %s" % str(args['origin'])
 
             try:
-                obj.mirror(axis, [dist, dist])
+                obj.mirror(axis, [x, y])
             except Exception as e:
                 return "Operation failed: %s" % str(e)

+ 1 - 1
tclCommands/TclCommandNew.py

@@ -24,7 +24,7 @@ class TclCommandNew(TclCommand):
     help = {
         'main': "Starts a new project. Clears objects from memory.",
         'args': collections.OrderedDict(),
-        'examples': []
+        'examples': ['new']
     }
 
     def execute(self, args, unnamed_args):

+ 1 - 1
tclCommands/TclCommandNewExcellon.py

@@ -39,7 +39,7 @@ class TclCommandNewExcellon(TclCommandSignaled):
         'args': collections.OrderedDict([
             ('name', 'New object name.'),
         ]),
-        'examples': []
+        'examples': ['new_excellon my_excellon', 'new_excellon']
     }
 
     def execute(self, args, unnamed_args):

+ 3 - 2
tclCommands/TclCommandNewGeometry.py

@@ -28,11 +28,12 @@ class TclCommandNewGeometry(TclCommandSignaled):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Creates a new empty geometry object.",
+        'main': "Creates a new empty Geometry object.",
         'args': collections.OrderedDict([
             ('name', 'New object name.'),
         ]),
-        'examples': []
+        'examples': ['new_geometry\n'
+                     'new_geometry my_new_geo']
     }
 
     def execute(self, args, unnamed_args):

+ 1 - 1
tclCommands/TclCommandNewGerber.py

@@ -39,7 +39,7 @@ class TclCommandNewGerber(TclCommandSignaled):
         'args': collections.OrderedDict([
             ('name', 'New object name.'),
         ]),
-        'examples': []
+        'examples': ['new_gerber', 'new_gerber my_new_gerber_name']
     }
 
     def execute(self, args, unnamed_args):

+ 2 - 2
tclCommands/TclCommandNregions.py

@@ -41,13 +41,13 @@ class TclCommandNregions(TclCommand):
     help = {
         'main': "Creates a geometry object with the non-copper regions.",
         'args': collections.OrderedDict([
-            ('name', 'Object name for which to create non-copper regions. String'),
+            ('name', 'Object name for which to create non-copper regions. String. Required.'),
             ('outname', 'Name of the resulting Geometry object. String.'),
             ('margin', "Specify the edge of the PCB by drawing a box around all objects with this minimum distance. "
                        "Float number."),
             ('rounded', "Resulting geometry will have rounded corners. True or False.")
         ]),
-        'examples': ['ncr name -outname name_ncr']
+        'examples': ['ncr name -margin 0.1 -rounded True -outname name_ncr']
     }
 
     def execute(self, args, unnamed_args):

+ 15 - 8
tclCommands/TclCommandOffset.py

@@ -23,21 +23,22 @@ class TclCommandOffset(TclCommand):
 
     # Dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
     option_types = collections.OrderedDict([
-
+        ('x', float),
+        ('y', float)
     ])
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
-    required = ['name', 'x', 'y']
+    required = ['name']
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Changes the position of the object.",
+        'main': "Changes the position of the object on X and/or Y axis.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the object to offset.'),
-            ('x', 'Offset distance in the X axis.'),
-            ('y', 'Offset distance in the Y axis')
+            ('name', 'Name of the object to offset. Required.'),
+            ('x', 'Offset distance in the X axis. If it is not used it will be assumed to be 0.0'),
+            ('y', 'Offset distance in the Y axis. If it is not used it will be assumed to be 0.0')
         ]),
-        'examples': ['offset my_geometry 1.2 -0.3']
+        'examples': ['offset my_geometry -x 1.2 -y -0.3', 'offset my_geometry -x 1.0']
     }
 
     def execute(self, args, unnamed_args):
@@ -49,6 +50,12 @@ class TclCommandOffset(TclCommand):
         """
 
         name = args['name']
-        x, y = float(args['x']), float(args['y'])
+        off_x = args['x'] if 'x' in args else 0.0
+        off_y = args['y'] if 'y' in args else 0.0
+
+        x, y = float(off_x), float(off_y)
+
+        if (x, y) == (0.0, 0.0):
+            return
 
         self.app.collection.get_by_name(name).offset((x, y))

+ 8 - 2
tclCommands/TclCommandOpenExcellon.py

@@ -30,10 +30,13 @@ class TclCommandOpenExcellon(TclCommandSignaled):
     help = {
         'main': "Opens an Excellon file.",
         'args': collections.OrderedDict([
-            ('filename', 'Path to file to open.'),
+            ('filename', 'Absolute path to file to open. Required.\n'
+                         'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
             ('outname', 'Name of the resulting Excellon object.')
         ]),
-        'examples': []
+        'examples': ['open_excellon D:\\my_excellon_file.DRL',
+                     'open_excellon "D:\\my_excellon_file with spaces in the name.DRL"',
+                     'open_excellon path_to_file']
     }
 
     def execute(self, args, unnamed_args):
@@ -48,6 +51,9 @@ class TclCommandOpenExcellon(TclCommandSignaled):
 
         filename = args.pop('filename')
         # filename = filename.replace(' ', '')
+        if ' ' in filename:
+            return "The absolute path to the project file contain spaces which is not allowed.\n" \
+                   "Please enclose the path within quotes."
 
         args['plot'] = False
         self.app.open_excellon(filename, **args)

+ 7 - 3
tclCommands/TclCommandOpenGCode.py

@@ -31,10 +31,12 @@ class TclCommandOpenGCode(TclCommandSignaled):
     help = {
         'main': "Opens a G-Code file.",
         'args': collections.OrderedDict([
-            ('filename', 'Path to file to open.'),
+            ('filename', 'Absolute path to file to open. Required.\n'
+                         'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
             ('outname', 'Name of the resulting CNCJob object.')
         ]),
-        'examples': []
+        'examples': ['open_gcode D:\\my_gcode_file.NC',
+                     'open_gcode "D:\\my_gcode_file with spaces in the name.TXT"']
     }
 
     def execute(self, args, unnamed_args):
@@ -48,6 +50,8 @@ class TclCommandOpenGCode(TclCommandSignaled):
         """
         args['plot'] = False
         filename = args["filename"]
-        # filename = filename.replace(' ', '')
+        if ' ' in filename:
+            return "The absolute path to the project file contain spaces which is not allowed.\n" \
+                   "Please enclose the path within quotes."
 
         self.app.open_gcode(filename, **args)

+ 8 - 3
tclCommands/TclCommandOpenGerber.py

@@ -30,10 +30,12 @@ class TclCommandOpenGerber(TclCommandSignaled):
     help = {
         'main': "Opens a Gerber file.",
         'args': collections.OrderedDict([
-            ('filename', 'Path to file to open.'),
+            ('filename', 'Absolute path to file to open. Required.\n'
+                         'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
             ('outname', 'Name of the resulting Gerber object.')
         ]),
-        'examples': ["open_gerber gerber_object_path -outname bla"]
+        'examples': ["open_gerber gerber_object_path -outname bla",
+                     'open_gerber "D:\\my_gerber_file with spaces in the name.GRB"']
     }
 
     def execute(self, args, unnamed_args):
@@ -65,7 +67,10 @@ class TclCommandOpenGerber(TclCommandSignaled):
                 return
 
         filename = args['filename']
-        # filename = filename.replace(' ', '')
+
+        if ' ' in filename:
+            return "The absolute path to the project file contain spaces which is not allowed.\n" \
+                   "Please enclose the path within quotes."
 
         if 'outname' in args:
             outname = args['outname']

+ 7 - 3
tclCommands/TclCommandOpenProject.py

@@ -30,9 +30,11 @@ class TclCommandOpenProject(TclCommandSignaled):
     help = {
         'main': "Opens a FlatCAM project.",
         'args': collections.OrderedDict([
-            ('filename', 'Path to file to open.'),
+            ('filename', 'Absolute path to file to open. Required.\n'
+                         'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
         ]),
-        'examples': []
+        'examples': ['open_project D:\\my_project_file.FlatPrj',
+                     'open_project "D:\\my_project_file with spaces in the name.FlatPrj"']
     }
 
     def execute(self, args, unnamed_args):
@@ -45,6 +47,8 @@ class TclCommandOpenProject(TclCommandSignaled):
         :return: None or exception
         """
         filename = args['filename']
-        filename = filename.replace(' ', '')
+        if ' ' in filename:
+            return "The absolute path to the project file contain spaces which is not allowed.\n" \
+                   "Please enclose the path within quotes."
 
         self.app.open_project(filename, cli=True, plot=False)

+ 3 - 3
tclCommands/TclCommandOptions.py

@@ -28,11 +28,11 @@ class TclCommandOptions(TclCommandSignaled):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Shows the settings for an object.",
+        'main': "Will return the options (settings) for an object as a string with values separated by \\n.",
         'args': collections.OrderedDict([
-            ('name', 'Object name.'),
+            ('name', 'Object name for which to return the options. Required.'),
         ]),
-        'examples': []
+        'examples': ['options obj_name']
     }
 
     def execute(self, args, unnamed_args):

+ 21 - 7
tclCommands/TclCommandPanelize.py

@@ -38,7 +38,7 @@ class TclCommandPanelize(TclCommand):
     ])
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
-    required = ['name', 'rows', 'columns']
+    required = ['name']
 
     # structured help for current command, args needs to be ordered
     help = {
@@ -54,7 +54,14 @@ class TclCommandPanelize(TclCommand):
             ('outname', 'Name of the new geometry object.'),
             ('run_threaded', 'False = non-threaded || True = threaded')
         ]),
-        'examples': []
+        'examples': [
+            'panelize obj_name',
+
+            'panel obj_name -rows 2 -columns 2 -spacing_columns 0.4 -spacing_rows 1.3 -box box_obj_name '
+            '-outname panelized_name',
+
+            'panel obj_name -columns 2 -box box_obj_name -outname panelized_name',
+        ]
     }
 
     def execute(self, args, unnamed_args):
@@ -85,8 +92,18 @@ class TclCommandPanelize(TclCommand):
         else:
             box = obj
 
-        if 'columns' not in args or 'rows' not in args:
-            return "ERROR: Specify -columns and -rows"
+        if 'columns' in args:
+            columns = int(args['columns'])
+        else:
+            columns = int(0)
+
+        if 'rows' in args:
+            rows = int(args['rows'])
+        else:
+            rows = int(0)
+
+        if 'columns' not in args and 'rows' not in args:
+            return "ERROR: Specify either -columns or -rows. The one not specified it will assumed to be 0"
 
         if 'outname' in args:
             outname = args['outname']
@@ -108,9 +125,6 @@ class TclCommandPanelize(TclCommand):
         else:
             spacing_rows = 5
 
-        rows = int(args['rows'])
-        columns = int(args['columns'])
-
         xmin, ymin, xmax, ymax = box.bounds()
         lenghtx = xmax - xmin + spacing_columns
         lenghty = ymax - ymin + spacing_rows

+ 1 - 1
tclCommands/TclCommandPlotAll.py

@@ -33,7 +33,7 @@ class TclCommandPlotAll(TclCommand):
         'args': collections.OrderedDict([
 
         ]),
-        'examples': []
+        'examples': ['plot_all']
     }
 
     def execute(self, args, unnamed_args):

+ 4 - 4
tclCommands/TclCommandPlotObjects.py

@@ -32,15 +32,15 @@ class TclCommandPlotObjects(TclCommand):
     ])
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
-    required = []
+    required = ['names']
 
     # 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.")
+            ('names', "A list of object names to be plotted separated by comma. Required.")
         ]),
-        'examples': ["plot_objects"]
+        'examples': ["plot_objects gerber_obj.GRB, excellon_obj.DRL"]
     }
 
     def execute(self, args, unnamed_args):
@@ -51,7 +51,7 @@ class TclCommandPlotObjects(TclCommand):
         :return:
         """
         if self.app.cmd_line_headless != 1:
-            names = [x.strip() for x in args['names'].split(",")]
+            names = [x.strip() for x in args['names'].split(",") if x != '']
             objs = []
             for name in names:
                 objs.append(self.app.collection.get_by_name(name))

+ 5 - 2
tclCommands/TclCommandSaveProject.py

@@ -30,9 +30,12 @@ class TclCommandSaveProject(TclCommandSignaled):
     help = {
         'main': "Saves the FlatCAM project to file.",
         'args': collections.OrderedDict([
-            ('filename', 'Path to file.'),
+            ('filename', 'Absolute path to file to open. Required.\n'
+                         'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
         ]),
-        'examples': []
+        'examples': ['save_project D:\\my_project_file.FlatPrj',
+                     'save_project "D:\\my_project_file with spaces in the name.FlatPrj"',
+                     'save_project path_to_where_the_file_is_stored']
     }
 
     def execute(self, args, unnamed_args):

+ 2 - 2
tclCommands/TclCommandSaveSys.py

@@ -33,9 +33,9 @@ class TclCommandSaveSys(TclCommandSignaled):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Saves the FlatCAM system paramaters to defaults file.",
+        'main': "Saves the FlatCAM system parameters to defaults file.",
         'args': collections.OrderedDict([]),
-        'examples': []
+        'examples': ['save_sys']
     }
 
     def execute(self, args, unnamed_args):

+ 21 - 8
tclCommands/TclCommandScale.py

@@ -45,18 +45,22 @@ class TclCommandScale(TclCommand):
     help = {
         'main': "Resizes the object by a factor on X axis and a factor on Y axis, having as scale origin the point ",
         'args': collections.OrderedDict([
-            ('name', 'Name of the object to resize.'),
-            ('factor', 'Fraction by which to scale on both axis. '),
+            ('name', 'Name of the object (Gerber, Geometry or Excellon) to be resized. Required.'),
+            ('factor', 'Fraction by which to scale on both axis.'),
             ('x', 'Fraction by which to scale on X axis. If "factor" is used then this parameter is ignored'),
             ('y', 'Fraction by which to scale on Y axis. If "factor" is used then this parameter is ignored'),
-            ('origin', 'Reference used for scale. It can be: "origin" which means point (0, 0) or "min_bounds" which '
-                       'means the lower left point of the bounding box or it can be "center" which means the center '
-                       'of the bounding box.')
+            ('origin', 'Reference used for scale.\n'
+                       'The reference point can be:\n'
+                       '- "origin" which means point (0, 0)\n'
+                       '- "min_bounds" which means the lower left point of the bounding box\n'
+                       '- "center" which means the center point of the bounding box of the object.\n'
+                       '- a tuple in format (x,y) with the X and Y coordinates separated by a comma. NO SPACES ALLOWED')
 
         ]),
         'examples': ['scale my_geometry 4.2',
                      'scale my_geo -x 3.1 -y 2.8',
-                     'scale my_geo 1.2 -origin min_bounds']
+                     'scale my_geo 1.2 -origin min_bounds',
+                     'scale my_geometry -x 2 -origin 3.0,2.1']
     }
 
     def execute(self, args, unnamed_args):
@@ -92,8 +96,17 @@ class TclCommandScale(TclCommand):
                 c_y = ymin + (ymax - ymin) / 2
                 point = (c_x, c_y)
             else:
-                self.raise_tcl_error('%s' % _("Expected -origin <origin> or -origin <min_bounds> or -origin <center>."))
-                return 'fail'
+                try:
+                    point = eval(args['origin'])
+                    if not isinstance(point, tuple):
+                        raise Exception
+                except Exception as e:
+                    self.raise_tcl_error('%s\n%s' % (_("Expected -origin <origin> or "
+                                                  "-origin <min_bounds> or "
+                                                  "-origin <center> or "
+                                                  "- origin 3.0,4.2."), str(e))
+                                         )
+                    return 'fail'
 
         if 'factor' in args:
             factor = float(args['factor'])

+ 2 - 2
tclCommands/TclCommandSetActive.py

@@ -31,9 +31,9 @@ class TclCommandSetActive(TclCommand):
     help = {
         'main': 'Sets an object as active.',
         'args': collections.OrderedDict([
-            ('name', 'Name of the Object.'),
+            ('name', 'Name of the FlatCAM object to be set as active (selected). Required.'),
         ]),
-        'examples': []
+        'examples': ['set_active object_name']
     }
 
     def execute(self, args, unnamed_args):

+ 5 - 3
tclCommands/TclCommandSetOrigin.py

@@ -49,13 +49,15 @@ class TclCommandSetOrigin(TclCommand):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Will set the origin at the specified x,y location.",
+        'main': "Will set the origin at the specified x,y location.\n"
+                "If it is called without arguments it will set origin at (0, 0)",
         'args': collections.OrderedDict([
-            ('loc', 'Location to offset all the selected objects. No spaces between x and y pair. Use like this: 2,3'),
+            ('loc', 'Location to offset all the selected objects. NO SPACES ALLOWED in X and Y pair.\n'
+                    'Use like this: 2,3'),
             ('auto', 'If set to True it will set the origin to the minimum x, y of the object selection bounding box.'
                      '-auto=True is not correct but -auto 1 or -auto True is correct.')
         ]),
-        'examples': ['set_origin 3,2', 'set_origin -auto 1']
+        'examples': ['set_origin 3,2', 'set_origin -auto 1', 'origin']
     }
 
     def execute(self, args, unnamed_args):

+ 2 - 2
tclCommands/TclCommandSetSys.py

@@ -32,10 +32,10 @@ class TclCommandSetSys(TclCommand):
     help = {
         'main': "Sets the value of the system variable.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the system variable.'),
+            ('name', 'Name of the system variable. Required.'),
             ('value', 'Value to set.')
         ]),
-        'examples': []
+        'examples': ['set_sys global_gridx 1.0']
     }
 
     def execute(self, args, unnamed_args):

+ 21 - 10
tclCommands/TclCommandSkew.py

@@ -17,28 +17,27 @@ class TclCommandSkew(TclCommand):
     # Dictionary of types from Tcl command, needs to be ordered
     arg_names = collections.OrderedDict([
         ('name', str),
-        ('angle_x', float),
-        ('angle_y', float)
     ])
 
     # Dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
     option_types = collections.OrderedDict([
-
+        ('x', float),
+        ('y', float)
     ])
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
-    required = ['name', 'angle_x', 'angle_y']
+    required = ['name']
 
     # structured help for current command, args needs to be ordered
     help = {
         'main': "Shear/Skew an object by angles along x and y dimensions. The reference point is the left corner of "
                 "the bounding box of the object.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the object to skew.'),
-            ('angle_x', 'Angle in degrees by which to skew on the X axis.'),
-            ('angle_y', 'Angle in degrees by which to skew on the Y axis.')
+            ('name', 'Name of the object (Gerber, Geometry or Excellon) to be deformed (skewed). Required.'),
+            ('x', 'Angle in degrees by which to skew on the X axis. If it is not used it will be assumed to be 0.0'),
+            ('y', 'Angle in degrees by which to skew on the Y axis. If it is not used it will be assumed to be 0.0')
         ]),
-        'examples': ['skew my_geometry 10.2 3.5']
+        'examples': ['skew my_geometry -x 10.2 -y 3.5', 'skew my_geo -x 3.0']
     }
 
     def execute(self, args, unnamed_args):
@@ -50,8 +49,20 @@ class TclCommandSkew(TclCommand):
         """
 
         name = args['name']
-        angle_x = float(args['angle_x'])
-        angle_y = float(args['angle_y'])
+
+        if 'x' in args:
+            angle_x = float(args['x'])
+        else:
+            angle_x = 0.0
+
+        if 'y' in args:
+            angle_y = float(args['y'])
+        else:
+            angle_y = 0.0
+
+        if angle_x == 0.0 and angle_y == 0.0:
+            # nothing to be done
+            return
 
         obj_to_skew = self.app.collection.get_by_name(name)
         xmin, ymin, xmax, ymax = obj_to_skew.bounds()

+ 5 - 3
tclCommands/TclCommandSubtractPoly.py

@@ -28,12 +28,14 @@ class TclCommandSubtractPoly(TclCommandSignaled):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Subtract polygon from the given Geometry object.",
+        'main': "Subtract polygon from the given Geometry object. The coordinates are provided in X Y pairs.\n"
+                "If the number of coordinates is not even then the 'Incomplete coordinate' error is raised.\n"
+                "If last coordinates are not the same as the first ones, the polygon will be completed automatically.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the Geometry object from which to subtract.'),
+            ('name', 'Name of the Geometry object from which to subtract. Required.'),
             ('x0 y0 x1 y1 x2 y2 ...', 'Points defining the polygon.')
         ]),
-        'examples': []
+        'examples': ['subtract_poly my_geo 0 0 2 1 3 3 4 4 0 0']
     }
 
     def execute(self, args, unnamed_args):

+ 3 - 2
tclCommands/TclCommandSubtractRectangle.py

@@ -36,9 +36,10 @@ class TclCommandSubtractRectangle(TclCommandSignaled):
 
     # structured help for current command, args needs to be ordered
     help = {
-        'main': "Subtract rectange from the given Geometry object.",
+        'main': "Subtract a rectangle from the given Geometry object. The coordinates are provided in X Y pairs.\n"
+                "If the number of coordinates is not even then the 'Incomplete coordinates' error is raised.",
         'args': collections.OrderedDict([
-            ('name', 'Name of the Geometry object from which to subtract.'),
+            ('name', 'Name of the Geometry object from which to subtract. Required.'),
             ('x0 y0', 'Bottom left corner coordinates.'),
             ('x1 y1', 'Top right corner coordinates.')
         ]),

+ 2 - 2
tclCommands/TclCommandWriteGCode.py

@@ -34,8 +34,8 @@ class TclCommandWriteGCode(TclCommandSignaled):
     help = {
         'main': "Saves G-code of a CNC Job object to file.",
         'args': collections.OrderedDict([
-            ('name', 'Source CNC Job object.'),
-            ('filename', 'Output filename.'),
+            ('name', 'Source CNC Job object. Required.'),
+            ('filename', 'Output filename. Required.'),
             ('preamble', 'Text to append at the beginning.'),
             ('postamble', 'Text to append at the end.'),
             ('muted', 'It will not put errors in the Shell or status bar.')