diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 4bdbc575..6f6d0919 100644 --- a/FlatCAMApp.py +++ b/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") diff --git a/README.md b/README.md index e115e7a8..678a9953 100644 --- a/README.md +++ b/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 diff --git a/tclCommands/TclCommandAddCircle.py b/tclCommands/TclCommandAddCircle.py index 181484d6..f48ece80 100644 --- a/tclCommands/TclCommandAddCircle.py +++ b/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): diff --git a/tclCommands/TclCommandAddRectangle.py b/tclCommands/TclCommandAddRectangle.py index fa26ae02..0fa7096e 100644 --- a/tclCommands/TclCommandAddRectangle.py +++ b/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): diff --git a/tclCommands/TclCommandAlignDrill.py b/tclCommands/TclCommandAlignDrill.py index e34c8afd..1659b2a4 100644 --- a/tclCommands/TclCommandAlignDrill.py +++ b/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'), diff --git a/tclCommands/TclCommandAlignDrillGrid.py b/tclCommands/TclCommandAlignDrillGrid.py index e15bd840..ac86f198 100644 --- a/tclCommands/TclCommandAlignDrillGrid.py +++ b/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.'), diff --git a/tclCommands/TclCommandBbox.py b/tclCommands/TclCommandBbox.py index 06cef7d8..a3df3d16 100644 --- a/tclCommands/TclCommandBbox.py +++ b/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.'), diff --git a/tclCommands/TclCommandBounds.py b/tclCommands/TclCommandBounds.py index e4d53c7b..a03a97c0 100644 --- a/tclCommands/TclCommandBounds.py +++ b/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). diff --git a/tclCommands/TclCommandClearShell.py b/tclCommands/TclCommandClearShell.py index d765367a..4672ecae 100644 --- a/tclCommands/TclCommandClearShell.py +++ b/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): diff --git a/tclCommands/TclCommandCutout.py b/tclCommands/TclCommandCutout.py index 3df71efb..c074fa8e 100644 --- a/tclCommands/TclCommandCutout.py +++ b/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): diff --git a/tclCommands/TclCommandDelete.py b/tclCommands/TclCommandDelete.py index c5deb08d..43a69693 100644 --- a/tclCommands/TclCommandDelete.py +++ b/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) diff --git a/tclCommands/TclCommandExportGcode.py b/tclCommands/TclCommandExportGcode.py index 23842c91..2981e272 100644 --- a/tclCommands/TclCommandExportGcode.py +++ b/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): diff --git a/tclCommands/TclCommandExportGerber.py b/tclCommands/TclCommandExportGerber.py index a4d27152..0fc7b0aa 100644 --- a/tclCommands/TclCommandExportGerber.py +++ b/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'] diff --git a/tclCommands/TclCommandExportSVG.py b/tclCommands/TclCommandExportSVG.py index ebe95bc6..bc6efce9 100644 --- a/tclCommands/TclCommandExportSVG.py +++ b/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.') ]), diff --git a/tclCommands/TclCommandExteriors.py b/tclCommands/TclCommandExteriors.py index e6a65503..cb3f041a 100644 --- a/tclCommands/TclCommandExteriors.py +++ b/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): diff --git a/tclCommands/TclCommandFollow.py b/tclCommands/TclCommandFollow.py index 59ad53ee..0ca8ab5e 100644 --- a/tclCommands/TclCommandFollow.py +++ b/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): diff --git a/tclCommands/TclCommandGeoCutout.py b/tclCommands/TclCommandGeoCutout.py index f7df8108..c138d4ad 100644 --- a/tclCommands/TclCommandGeoCutout.py +++ b/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" + diff --git a/tclCommands/TclCommandGeoUnion.py b/tclCommands/TclCommandGeoUnion.py index b0be4734..ac4fa4ea 100644 --- a/tclCommands/TclCommandGeoUnion.py +++ b/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): diff --git a/tclCommands/TclCommandGetNames.py b/tclCommands/TclCommandGetNames.py index 6b597f6f..7cca9a46 100644 --- a/tclCommands/TclCommandGetNames.py +++ b/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): diff --git a/tclCommands/TclCommandGetSys.py b/tclCommands/TclCommandGetSys.py index 915ac18e..f98c3315 100644 --- a/tclCommands/TclCommandGetSys.py +++ b/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'] } diff --git a/tclCommands/TclCommandImportSvg.py b/tclCommands/TclCommandImportSvg.py index 6489db15..0617090e 100644 --- a/tclCommands/TclCommandImportSvg.py +++ b/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): diff --git a/tclCommands/TclCommandInteriors.py b/tclCommands/TclCommandInteriors.py index d4a1adb3..f22ef1db 100644 --- a/tclCommands/TclCommandInteriors.py +++ b/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): diff --git a/tclCommands/TclCommandIsolate.py b/tclCommands/TclCommandIsolate.py index f2864303..542dd3c3 100644 --- a/tclCommands/TclCommandIsolate.py +++ b/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) diff --git a/tclCommands/TclCommandJoinExcellon.py b/tclCommands/TclCommandJoinExcellon.py index efe6290e..c385b55c 100644 --- a/tclCommands/TclCommandJoinExcellon.py +++ b/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." diff --git a/tclCommands/TclCommandJoinGeometry.py b/tclCommands/TclCommandJoinGeometry.py index 74036d80..d3208877 100644 --- a/tclCommands/TclCommandJoinGeometry.py +++ b/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." diff --git a/tclCommands/TclCommandListSys.py b/tclCommands/TclCommandListSys.py index 58d8c8e3..cff9ca06 100644 --- a/tclCommands/TclCommandListSys.py +++ b/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', diff --git a/tclCommands/TclCommandMillDrills.py b/tclCommands/TclCommandMillDrills.py index a7d607c2..1e8684d0 100644 --- a/tclCommands/TclCommandMillDrills.py +++ b/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 != ''] diff --git a/tclCommands/TclCommandMillSlots.py b/tclCommands/TclCommandMillSlots.py index 9665c91d..af6070be 100644 --- a/tclCommands/TclCommandMillSlots.py +++ b/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): diff --git a/tclCommands/TclCommandMirror.py b/tclCommands/TclCommandMirror.py index 819f26ef..cc29852f 100644 --- a/tclCommands/TclCommandMirror.py +++ b/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) diff --git a/tclCommands/TclCommandNew.py b/tclCommands/TclCommandNew.py index 757412d3..66ff83b9 100644 --- a/tclCommands/TclCommandNew.py +++ b/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): diff --git a/tclCommands/TclCommandNewExcellon.py b/tclCommands/TclCommandNewExcellon.py index 2c540fe1..c1322133 100644 --- a/tclCommands/TclCommandNewExcellon.py +++ b/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): diff --git a/tclCommands/TclCommandNewGeometry.py b/tclCommands/TclCommandNewGeometry.py index 089b2c50..4af616c6 100644 --- a/tclCommands/TclCommandNewGeometry.py +++ b/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): diff --git a/tclCommands/TclCommandNewGerber.py b/tclCommands/TclCommandNewGerber.py index bccbd923..7a667813 100644 --- a/tclCommands/TclCommandNewGerber.py +++ b/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): diff --git a/tclCommands/TclCommandNregions.py b/tclCommands/TclCommandNregions.py index 6dbb22d5..a4146792 100644 --- a/tclCommands/TclCommandNregions.py +++ b/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): diff --git a/tclCommands/TclCommandOffset.py b/tclCommands/TclCommandOffset.py index a7306db9..6f5fd1c7 100644 --- a/tclCommands/TclCommandOffset.py +++ b/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)) diff --git a/tclCommands/TclCommandOpenExcellon.py b/tclCommands/TclCommandOpenExcellon.py index c9f32409..167db227 100644 --- a/tclCommands/TclCommandOpenExcellon.py +++ b/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) diff --git a/tclCommands/TclCommandOpenGCode.py b/tclCommands/TclCommandOpenGCode.py index d4da1423..5eaa83c9 100644 --- a/tclCommands/TclCommandOpenGCode.py +++ b/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) diff --git a/tclCommands/TclCommandOpenGerber.py b/tclCommands/TclCommandOpenGerber.py index 0b67f83c..037882a1 100644 --- a/tclCommands/TclCommandOpenGerber.py +++ b/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'] diff --git a/tclCommands/TclCommandOpenProject.py b/tclCommands/TclCommandOpenProject.py index ef0775af..3dddad61 100644 --- a/tclCommands/TclCommandOpenProject.py +++ b/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) diff --git a/tclCommands/TclCommandOptions.py b/tclCommands/TclCommandOptions.py index 4bc90b84..ab22599e 100644 --- a/tclCommands/TclCommandOptions.py +++ b/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): diff --git a/tclCommands/TclCommandPanelize.py b/tclCommands/TclCommandPanelize.py index b40cc434..71d50199 100644 --- a/tclCommands/TclCommandPanelize.py +++ b/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 diff --git a/tclCommands/TclCommandPlotAll.py b/tclCommands/TclCommandPlotAll.py index 2e8ead22..d3833dd0 100644 --- a/tclCommands/TclCommandPlotAll.py +++ b/tclCommands/TclCommandPlotAll.py @@ -33,7 +33,7 @@ class TclCommandPlotAll(TclCommand): 'args': collections.OrderedDict([ ]), - 'examples': [] + 'examples': ['plot_all'] } def execute(self, args, unnamed_args): diff --git a/tclCommands/TclCommandPlotObjects.py b/tclCommands/TclCommandPlotObjects.py index bc3978a3..1df57886 100644 --- a/tclCommands/TclCommandPlotObjects.py +++ b/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)) diff --git a/tclCommands/TclCommandSaveProject.py b/tclCommands/TclCommandSaveProject.py index 9eaa1bbe..899247a2 100644 --- a/tclCommands/TclCommandSaveProject.py +++ b/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): diff --git a/tclCommands/TclCommandSaveSys.py b/tclCommands/TclCommandSaveSys.py index 9b18ba80..5712515b 100644 --- a/tclCommands/TclCommandSaveSys.py +++ b/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): diff --git a/tclCommands/TclCommandScale.py b/tclCommands/TclCommandScale.py index 8f68ee92..aa5ebc3e 100644 --- a/tclCommands/TclCommandScale.py +++ b/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 or -origin or -origin
.")) - 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 or " + "-origin or " + "-origin
or " + "- origin 3.0,4.2."), str(e)) + ) + return 'fail' if 'factor' in args: factor = float(args['factor']) diff --git a/tclCommands/TclCommandSetActive.py b/tclCommands/TclCommandSetActive.py index 2c51b72c..5144289a 100644 --- a/tclCommands/TclCommandSetActive.py +++ b/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): diff --git a/tclCommands/TclCommandSetOrigin.py b/tclCommands/TclCommandSetOrigin.py index 52974dd2..895338e4 100644 --- a/tclCommands/TclCommandSetOrigin.py +++ b/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): diff --git a/tclCommands/TclCommandSetSys.py b/tclCommands/TclCommandSetSys.py index 9d477e27..a8133317 100644 --- a/tclCommands/TclCommandSetSys.py +++ b/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): diff --git a/tclCommands/TclCommandSkew.py b/tclCommands/TclCommandSkew.py index 60902b10..28da6e1c 100644 --- a/tclCommands/TclCommandSkew.py +++ b/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() diff --git a/tclCommands/TclCommandSubtractPoly.py b/tclCommands/TclCommandSubtractPoly.py index f5b08fd1..98c43c66 100644 --- a/tclCommands/TclCommandSubtractPoly.py +++ b/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): diff --git a/tclCommands/TclCommandSubtractRectangle.py b/tclCommands/TclCommandSubtractRectangle.py index 53f99bf6..2453c584 100644 --- a/tclCommands/TclCommandSubtractRectangle.py +++ b/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.') ]), diff --git a/tclCommands/TclCommandWriteGCode.py b/tclCommands/TclCommandWriteGCode.py index 7125706e..655f00cb 100644 --- a/tclCommands/TclCommandWriteGCode.py +++ b/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.')