Przeglądaj źródła

jpcgt/flatcam/Beta слито с Beta

Camellan 6 lat temu
rodzic
commit
5569c68670
45 zmienionych plików z 1030 dodań i 549 usunięć
  1. 207 108
      FlatCAMApp.py
  2. 63 53
      FlatCAMObj.py
  3. 1 1
      ObjectCollection.py
  4. 24 0
      README.md
  5. 34 20
      camlib.py
  6. 302 237
      flatcamGUI/FlatCAMGUI.py
  7. 8 3
      flatcamGUI/ObjectUI.py
  8. 1 1
      flatcamTools/ToolFilm.py
  9. 8 3
      flatcamTools/ToolNonCopperClear.py
  10. 40 17
      flatcamTools/ToolPaint.py
  11. BIN
      share/bug16.png
  12. BIN
      share/bug32.png
  13. BIN
      share/pdf_link16.png
  14. 28 30
      tclCommands/TclCommand.py
  15. 13 7
      tclCommands/TclCommandAlignDrill.py
  16. 11 5
      tclCommands/TclCommandAlignDrillGrid.py
  17. 1 1
      tclCommands/TclCommandBbox.py
  18. 30 12
      tclCommands/TclCommandCncjob.py
  19. 2 0
      tclCommands/TclCommandCopperClear.py
  20. 1 1
      tclCommands/TclCommandCutout.py
  21. 19 7
      tclCommands/TclCommandDrillcncjob.py
  22. 1 1
      tclCommands/TclCommandExteriors.py
  23. 2 2
      tclCommands/TclCommandGeoCutout.py
  24. 1 1
      tclCommands/TclCommandImportSvg.py
  25. 1 1
      tclCommands/TclCommandIsolate.py
  26. 1 1
      tclCommands/TclCommandJoinExcellon.py
  27. 1 1
      tclCommands/TclCommandJoinGeometry.py
  28. 1 1
      tclCommands/TclCommandMillDrills.py
  29. 1 1
      tclCommands/TclCommandMillSlots.py
  30. 0 1
      tclCommands/TclCommandMirror.py
  31. 1 1
      tclCommands/TclCommandNew.py
  32. 51 0
      tclCommands/TclCommandNewExcellon.py
  33. 6 4
      tclCommands/TclCommandNewGeometry.py
  34. 68 0
      tclCommands/TclCommandNewGerber.py
  35. 1 1
      tclCommands/TclCommandNregions.py
  36. 2 0
      tclCommands/TclCommandOpenExcellon.py
  37. 4 1
      tclCommands/TclCommandOpenGCode.py
  38. 5 12
      tclCommands/TclCommandOpenGerber.py
  39. 3 1
      tclCommands/TclCommandOpenProject.py
  40. 9 3
      tclCommands/TclCommandPaint.py
  41. 3 3
      tclCommands/TclCommandPanelize.py
  42. 2 2
      tclCommands/TclCommandPlotAll.py
  43. 51 0
      tclCommands/TclCommandPlotObjects.py
  44. 18 4
      tclCommands/TclCommandWriteGCode.py
  45. 4 1
      tclCommands/__init__.py

+ 207 - 108
FlatCAMApp.py

@@ -124,6 +124,10 @@ class App(QtCore.QObject):
     # Manual URL
     # Manual URL
     manual_url = "http://flatcam.org/manual/index.html"
     manual_url = "http://flatcam.org/manual/index.html"
     video_url = "https://www.youtube.com/playlist?list=PLVvP2SYRpx-AQgNlfoxw93tXUXon7G94_"
     video_url = "https://www.youtube.com/playlist?list=PLVvP2SYRpx-AQgNlfoxw93tXUXon7G94_"
+    gerber_spec_url ="https://www.ucamco.com/files/downloads/file/81/The_Gerber_File_Format_specification." \
+                     "pdf?7ac957791daba2cdf4c2c913f67a43da"
+    excellon_spec_url = "https://www.ucamco.com/files/downloads/file/305/the_xnc_file_format_specification.pdf"
+    bug_report_url = "https://bitbucket.org/jpcgt/flatcam/issues?status=new&status=open"
 
 
     # this variable will hold the project status
     # this variable will hold the project status
     # if True it will mean that the project was modified and not saved
     # if True it will mean that the project was modified and not saved
@@ -401,20 +405,15 @@ class App(QtCore.QObject):
             "global_portable": self.ui.general_defaults_form.general_app_group.portability_cb,
             "global_portable": self.ui.general_defaults_form.general_app_group.portability_cb,
             "global_language": self.ui.general_defaults_form.general_app_group.language_cb,
             "global_language": self.ui.general_defaults_form.general_app_group.language_cb,
 
 
-            "global_shell_at_startup": self.ui.general_defaults_form.general_app_group.shell_startup_cb,
             "global_version_check": self.ui.general_defaults_form.general_app_group.version_check_cb,
             "global_version_check": self.ui.general_defaults_form.general_app_group.version_check_cb,
             "global_send_stats": self.ui.general_defaults_form.general_app_group.send_stats_cb,
             "global_send_stats": self.ui.general_defaults_form.general_app_group.send_stats_cb,
             "global_pan_button": self.ui.general_defaults_form.general_app_group.pan_button_radio,
             "global_pan_button": self.ui.general_defaults_form.general_app_group.pan_button_radio,
             "global_mselect_key": self.ui.general_defaults_form.general_app_group.mselect_radio,
             "global_mselect_key": self.ui.general_defaults_form.general_app_group.mselect_radio,
 
 
-            "global_project_at_startup": self.ui.general_defaults_form.general_app_group.project_startup_cb,
-            "global_project_autohide": self.ui.general_defaults_form.general_app_group.project_autohide_cb,
-            "global_toggle_tooltips": self.ui.general_defaults_form.general_app_group.toggle_tooltips_cb,
             "global_worker_number": self.ui.general_defaults_form.general_app_group.worker_number_sb,
             "global_worker_number": self.ui.general_defaults_form.general_app_group.worker_number_sb,
             "global_tolerance": self.ui.general_defaults_form.general_app_group.tol_entry,
             "global_tolerance": self.ui.general_defaults_form.general_app_group.tol_entry,
 
 
             "global_open_style": self.ui.general_defaults_form.general_app_group.open_style_cb,
             "global_open_style": self.ui.general_defaults_form.general_app_group.open_style_cb,
-            "global_delete_confirmation": self.ui.general_defaults_form.general_app_group.delete_conf_cb,
 
 
             "global_compression_level": self.ui.general_defaults_form.general_app_group.compress_combo,
             "global_compression_level": self.ui.general_defaults_form.general_app_group.compress_combo,
             "global_save_compressed": self.ui.general_defaults_form.general_app_group.save_type_cb,
             "global_save_compressed": self.ui.general_defaults_form.general_app_group.save_type_cb,
@@ -442,15 +441,17 @@ class App(QtCore.QObject):
             "global_layout": self.ui.general_defaults_form.general_gui_set_group.layout_combo,
             "global_layout": self.ui.general_defaults_form.general_gui_set_group.layout_combo,
             "global_hover": self.ui.general_defaults_form.general_gui_set_group.hover_cb,
             "global_hover": self.ui.general_defaults_form.general_gui_set_group.hover_cb,
             "global_selection_shape": self.ui.general_defaults_form.general_gui_set_group.selection_cb,
             "global_selection_shape": self.ui.general_defaults_form.general_gui_set_group.selection_cb,
+            "global_shell_at_startup": self.ui.general_defaults_form.general_gui_set_group.shell_startup_cb,
+            "global_project_at_startup": self.ui.general_defaults_form.general_gui_set_group.project_startup_cb,
+            "global_project_autohide": self.ui.general_defaults_form.general_gui_set_group.project_autohide_cb,
+            "global_toggle_tooltips": self.ui.general_defaults_form.general_gui_set_group.toggle_tooltips_cb,
+            "global_delete_confirmation": self.ui.general_defaults_form.general_gui_set_group.delete_conf_cb,
 
 
             # Gerber General
             # Gerber General
             "gerber_plot": self.ui.gerber_defaults_form.gerber_gen_group.plot_cb,
             "gerber_plot": self.ui.gerber_defaults_form.gerber_gen_group.plot_cb,
             "gerber_solid": self.ui.gerber_defaults_form.gerber_gen_group.solid_cb,
             "gerber_solid": self.ui.gerber_defaults_form.gerber_gen_group.solid_cb,
             "gerber_multicolored": self.ui.gerber_defaults_form.gerber_gen_group.multicolored_cb,
             "gerber_multicolored": self.ui.gerber_defaults_form.gerber_gen_group.multicolored_cb,
             "gerber_circle_steps": self.ui.gerber_defaults_form.gerber_gen_group.circle_steps_entry,
             "gerber_circle_steps": self.ui.gerber_defaults_form.gerber_gen_group.circle_steps_entry,
-            "gerber_buffering": self.ui.gerber_defaults_form.gerber_gen_group.buffering_radio,
-            "gerber_simplification": self.ui.gerber_defaults_form.gerber_gen_group.simplify_cb,
-            "gerber_simp_tolerance": self.ui.gerber_defaults_form.gerber_gen_group.simplification_tol_spinner,
 
 
             # Gerber Options
             # Gerber Options
             "gerber_isotooldia": self.ui.gerber_defaults_form.gerber_opt_group.iso_tool_dia_entry,
             "gerber_isotooldia": self.ui.gerber_defaults_form.gerber_opt_group.iso_tool_dia_entry,
@@ -468,6 +469,9 @@ class App(QtCore.QObject):
             # "gerber_aperture_scale_factor": self.ui.gerber_defaults_form.gerber_adv_opt_group.scale_aperture_entry,
             # "gerber_aperture_scale_factor": self.ui.gerber_defaults_form.gerber_adv_opt_group.scale_aperture_entry,
             # "gerber_aperture_buffer_factor": self.ui.gerber_defaults_form.gerber_adv_opt_group.buffer_aperture_entry,
             # "gerber_aperture_buffer_factor": self.ui.gerber_defaults_form.gerber_adv_opt_group.buffer_aperture_entry,
             "gerber_follow": self.ui.gerber_defaults_form.gerber_adv_opt_group.follow_cb,
             "gerber_follow": self.ui.gerber_defaults_form.gerber_adv_opt_group.follow_cb,
+            "gerber_buffering": self.ui.gerber_defaults_form.gerber_adv_opt_group.buffering_radio,
+            "gerber_simplification": self.ui.gerber_defaults_form.gerber_adv_opt_group.simplify_cb,
+            "gerber_simp_tolerance": self.ui.gerber_defaults_form.gerber_adv_opt_group.simplification_tol_spinner,
 
 
             # Gerber Export
             # Gerber Export
             "gerber_exp_units": self.ui.gerber_defaults_form.gerber_exp_group.gerber_units_radio,
             "gerber_exp_units": self.ui.gerber_defaults_form.gerber_exp_group.gerber_units_radio,
@@ -513,9 +517,9 @@ class App(QtCore.QObject):
             # Excellon Options
             # Excellon Options
             "excellon_drillz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry,
             "excellon_drillz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry,
             "excellon_travelz": self.ui.excellon_defaults_form.excellon_opt_group.travelz_entry,
             "excellon_travelz": self.ui.excellon_defaults_form.excellon_opt_group.travelz_entry,
+            "excellon_endz": self.ui.excellon_defaults_form.excellon_opt_group.eendz_entry,
             "excellon_feedrate": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_entry,
             "excellon_feedrate": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_entry,
             "excellon_spindlespeed": self.ui.excellon_defaults_form.excellon_opt_group.spindlespeed_entry,
             "excellon_spindlespeed": self.ui.excellon_defaults_form.excellon_opt_group.spindlespeed_entry,
-            "excellon_spindledir": self.ui.excellon_defaults_form.excellon_opt_group.spindledir_radio,
             "excellon_dwell": self.ui.excellon_defaults_form.excellon_opt_group.dwell_cb,
             "excellon_dwell": self.ui.excellon_defaults_form.excellon_opt_group.dwell_cb,
             "excellon_dwelltime": self.ui.excellon_defaults_form.excellon_opt_group.dwelltime_entry,
             "excellon_dwelltime": self.ui.excellon_defaults_form.excellon_opt_group.dwelltime_entry,
             "excellon_toolchange": self.ui.excellon_defaults_form.excellon_opt_group.toolchange_cb,
             "excellon_toolchange": self.ui.excellon_defaults_form.excellon_opt_group.toolchange_cb,
@@ -529,10 +533,10 @@ class App(QtCore.QObject):
             "excellon_offset": self.ui.excellon_defaults_form.excellon_adv_opt_group.offset_entry,
             "excellon_offset": self.ui.excellon_defaults_form.excellon_adv_opt_group.offset_entry,
             "excellon_toolchangexy": self.ui.excellon_defaults_form.excellon_adv_opt_group.toolchangexy_entry,
             "excellon_toolchangexy": self.ui.excellon_defaults_form.excellon_adv_opt_group.toolchangexy_entry,
             "excellon_startz": self.ui.excellon_defaults_form.excellon_adv_opt_group.estartz_entry,
             "excellon_startz": self.ui.excellon_defaults_form.excellon_adv_opt_group.estartz_entry,
-            "excellon_endz": self.ui.excellon_defaults_form.excellon_adv_opt_group.eendz_entry,
             "excellon_feedrate_rapid": self.ui.excellon_defaults_form.excellon_adv_opt_group.feedrate_rapid_entry,
             "excellon_feedrate_rapid": self.ui.excellon_defaults_form.excellon_adv_opt_group.feedrate_rapid_entry,
             "excellon_z_pdepth": self.ui.excellon_defaults_form.excellon_adv_opt_group.pdepth_entry,
             "excellon_z_pdepth": self.ui.excellon_defaults_form.excellon_adv_opt_group.pdepth_entry,
             "excellon_feedrate_probe": self.ui.excellon_defaults_form.excellon_adv_opt_group.feedrate_probe_entry,
             "excellon_feedrate_probe": self.ui.excellon_defaults_form.excellon_adv_opt_group.feedrate_probe_entry,
+            "excellon_spindledir": self.ui.excellon_defaults_form.excellon_adv_opt_group.spindledir_radio,
             "excellon_f_plunge": self.ui.excellon_defaults_form.excellon_adv_opt_group.fplunge_cb,
             "excellon_f_plunge": self.ui.excellon_defaults_form.excellon_adv_opt_group.fplunge_cb,
             "excellon_f_retract": self.ui.excellon_defaults_form.excellon_adv_opt_group.fretract_cb,
             "excellon_f_retract": self.ui.excellon_defaults_form.excellon_adv_opt_group.fretract_cb,
 
 
@@ -585,23 +589,23 @@ class App(QtCore.QObject):
             "geometry_feedrate": self.ui.geometry_defaults_form.geometry_opt_group.cncfeedrate_entry,
             "geometry_feedrate": self.ui.geometry_defaults_form.geometry_opt_group.cncfeedrate_entry,
             "geometry_feedrate_z": self.ui.geometry_defaults_form.geometry_opt_group.cncplunge_entry,
             "geometry_feedrate_z": self.ui.geometry_defaults_form.geometry_opt_group.cncplunge_entry,
             "geometry_spindlespeed": self.ui.geometry_defaults_form.geometry_opt_group.cncspindlespeed_entry,
             "geometry_spindlespeed": self.ui.geometry_defaults_form.geometry_opt_group.cncspindlespeed_entry,
-            "geometry_spindledir": self.ui.geometry_defaults_form.geometry_opt_group.spindledir_radio,
             "geometry_dwell": self.ui.geometry_defaults_form.geometry_opt_group.dwell_cb,
             "geometry_dwell": self.ui.geometry_defaults_form.geometry_opt_group.dwell_cb,
             "geometry_dwelltime": self.ui.geometry_defaults_form.geometry_opt_group.dwelltime_entry,
             "geometry_dwelltime": self.ui.geometry_defaults_form.geometry_opt_group.dwelltime_entry,
             "geometry_ppname_g": self.ui.geometry_defaults_form.geometry_opt_group.pp_geometry_name_cb,
             "geometry_ppname_g": self.ui.geometry_defaults_form.geometry_opt_group.pp_geometry_name_cb,
             "geometry_toolchange": self.ui.geometry_defaults_form.geometry_opt_group.toolchange_cb,
             "geometry_toolchange": self.ui.geometry_defaults_form.geometry_opt_group.toolchange_cb,
             "geometry_toolchangez": self.ui.geometry_defaults_form.geometry_opt_group.toolchangez_entry,
             "geometry_toolchangez": self.ui.geometry_defaults_form.geometry_opt_group.toolchangez_entry,
+            "geometry_endz": self.ui.geometry_defaults_form.geometry_opt_group.gendz_entry,
             "geometry_depthperpass": self.ui.geometry_defaults_form.geometry_opt_group.depthperpass_entry,
             "geometry_depthperpass": self.ui.geometry_defaults_form.geometry_opt_group.depthperpass_entry,
             "geometry_multidepth": self.ui.geometry_defaults_form.geometry_opt_group.multidepth_cb,
             "geometry_multidepth": self.ui.geometry_defaults_form.geometry_opt_group.multidepth_cb,
 
 
             # Geometry Advanced Options
             # Geometry Advanced Options
             "geometry_toolchangexy": self.ui.geometry_defaults_form.geometry_adv_opt_group.toolchangexy_entry,
             "geometry_toolchangexy": self.ui.geometry_defaults_form.geometry_adv_opt_group.toolchangexy_entry,
             "geometry_startz": self.ui.geometry_defaults_form.geometry_adv_opt_group.gstartz_entry,
             "geometry_startz": self.ui.geometry_defaults_form.geometry_adv_opt_group.gstartz_entry,
-            "geometry_endz": self.ui.geometry_defaults_form.geometry_adv_opt_group.gendz_entry,
             "geometry_feedrate_rapid": self.ui.geometry_defaults_form.geometry_adv_opt_group.cncfeedrate_rapid_entry,
             "geometry_feedrate_rapid": self.ui.geometry_defaults_form.geometry_adv_opt_group.cncfeedrate_rapid_entry,
             "geometry_extracut": self.ui.geometry_defaults_form.geometry_adv_opt_group.extracut_cb,
             "geometry_extracut": self.ui.geometry_defaults_form.geometry_adv_opt_group.extracut_cb,
             "geometry_z_pdepth": self.ui.geometry_defaults_form.geometry_adv_opt_group.pdepth_entry,
             "geometry_z_pdepth": self.ui.geometry_defaults_form.geometry_adv_opt_group.pdepth_entry,
             "geometry_feedrate_probe": self.ui.geometry_defaults_form.geometry_adv_opt_group.feedrate_probe_entry,
             "geometry_feedrate_probe": self.ui.geometry_defaults_form.geometry_adv_opt_group.feedrate_probe_entry,
+            "geometry_spindledir": self.ui.geometry_defaults_form.geometry_adv_opt_group.spindledir_radio,
             "geometry_f_plunge": self.ui.geometry_defaults_form.geometry_adv_opt_group.fplunge_cb,
             "geometry_f_plunge": self.ui.geometry_defaults_form.geometry_adv_opt_group.fplunge_cb,
             "geometry_segx": self.ui.geometry_defaults_form.geometry_adv_opt_group.segx_entry,
             "geometry_segx": self.ui.geometry_defaults_form.geometry_adv_opt_group.segx_entry,
             "geometry_segy": self.ui.geometry_defaults_form.geometry_adv_opt_group.segy_entry,
             "geometry_segy": self.ui.geometry_defaults_form.geometry_adv_opt_group.segy_entry,
@@ -613,8 +617,6 @@ class App(QtCore.QObject):
             "cncjob_plot": self.ui.cncjob_defaults_form.cncjob_gen_group.plot_cb,
             "cncjob_plot": self.ui.cncjob_defaults_form.cncjob_gen_group.plot_cb,
             "cncjob_plot_kind": self.ui.cncjob_defaults_form.cncjob_gen_group.cncplot_method_radio,
             "cncjob_plot_kind": self.ui.cncjob_defaults_form.cncjob_gen_group.cncplot_method_radio,
             "cncjob_annotation": self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_cb,
             "cncjob_annotation": self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_cb,
-            "cncjob_annotation_fontsize": self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontsize_sp,
-            "cncjob_annotation_fontcolor": self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontcolor_entry,
 
 
             "cncjob_tooldia": self.ui.cncjob_defaults_form.cncjob_gen_group.tooldia_entry,
             "cncjob_tooldia": self.ui.cncjob_defaults_form.cncjob_gen_group.tooldia_entry,
             "cncjob_coords_type": self.ui.cncjob_defaults_form.cncjob_gen_group.coords_type_radio,
             "cncjob_coords_type": self.ui.cncjob_defaults_form.cncjob_gen_group.coords_type_radio,
@@ -629,6 +631,8 @@ class App(QtCore.QObject):
             # CNC Job Advanced Options
             # CNC Job Advanced Options
             "cncjob_toolchange_macro": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.toolchange_text,
             "cncjob_toolchange_macro": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.toolchange_text,
             "cncjob_toolchange_macro_enable": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.toolchange_cb,
             "cncjob_toolchange_macro_enable": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.toolchange_cb,
+            "cncjob_annotation_fontsize": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontsize_sp,
+            "cncjob_annotation_fontcolor": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_entry,
 
 
             # NCC Tool
             # NCC Tool
             "tools_ncctools": self.ui.tools_defaults_form.tools_ncc_group.ncc_tool_dia_entry,
             "tools_ncctools": self.ui.tools_defaults_form.tools_ncc_group.ncc_tool_dia_entry,
@@ -677,6 +681,7 @@ class App(QtCore.QObject):
             "tools_film_type": self.ui.tools_defaults_form.tools_film_group.film_type_radio,
             "tools_film_type": self.ui.tools_defaults_form.tools_film_group.film_type_radio,
             "tools_film_boundary": self.ui.tools_defaults_form.tools_film_group.film_boundary_entry,
             "tools_film_boundary": self.ui.tools_defaults_form.tools_film_group.film_boundary_entry,
             "tools_film_scale": self.ui.tools_defaults_form.tools_film_group.film_scale_entry,
             "tools_film_scale": self.ui.tools_defaults_form.tools_film_group.film_scale_entry,
+            "tools_film_color": self.ui.tools_defaults_form.tools_film_group.film_color_entry,
 
 
             # Panelize Tool
             # Panelize Tool
             "tools_panelize_spacing_columns": self.ui.tools_defaults_form.tools_panelize_group.pspacing_columns,
             "tools_panelize_spacing_columns": self.ui.tools_defaults_form.tools_panelize_group.pspacing_columns,
@@ -846,6 +851,22 @@ class App(QtCore.QObject):
             "global_point_clipboard_format": "(%.4f, %.4f)",
             "global_point_clipboard_format": "(%.4f, %.4f)",
             "global_zdownrate": None,
             "global_zdownrate": None,
 
 
+            # autocomplete keywords
+            "global_autocomplete_keywords":
+                ['all', 'angle_x', 'angle_y', 'axis', 'axisoffset', 'box', 'center_x', 'center_y',
+                 'columns', 'combine', 'connect', 'contour', 'depthperpass', 'dia', 'diatol', 'dist',
+                 'drilled_dias', 'drillz', 'pp',
+                 'gridoffsety', 'gridx', 'gridy', 'has_offset', 'holes', 'margin', 'method',
+                 'milled_dias',
+                 'minoffset', 'multidepth', 'name', 'offset', 'opt_type', 'order', 'outname',
+                 'overlap', 'passes', 'postamble', 'ppname_e', 'ppname_g', 'preamble', 'radius', 'ref',
+                 'rest', 'rows', 'scale_factor', 'spacing_columns', 'spacing_rows', 'spindlespeed',
+                 'use_threads', 'value', 'x', 'x0', 'x1', 'y', 'y0', 'y1', 'z_cut', 'z_move',
+                 'default', 'feedrate_z', 'grbl_11', 'grbl_laser', 'hpgl', 'line_xyz', 'marlin',
+                 'Paste_1', 'Repetier', 'Toolchange_Custom', 'Roland_MDX_20', 'Toolchange_manual',
+                 'Toolchange_Probe_MACH3', 'dwell', 'dwelltime', 'toolchange_xy', 'iso_type',
+                 'Desktop', 'FlatPrj', 'FlatConfig', 'Users', 'Documents', 'My Documents', 'Marius'
+                 ],
             # General GUI Settings
             # General GUI Settings
             "global_hover": False,
             "global_hover": False,
             "global_selection_shape": True,
             "global_selection_shape": True,
@@ -857,9 +878,6 @@ class App(QtCore.QObject):
             "gerber_multicolored": False,
             "gerber_multicolored": False,
             "gerber_circle_steps": 128,
             "gerber_circle_steps": 128,
             "gerber_use_buffer_for_union": True,
             "gerber_use_buffer_for_union": True,
-            "gerber_buffering": "full",
-            "gerber_simplification": False,
-            "gerber_simp_tolerance": 0.0005,
 
 
             # Gerber Options
             # Gerber Options
             "gerber_isotooldia": 0.00787402,
             "gerber_isotooldia": 0.00787402,
@@ -877,6 +895,9 @@ class App(QtCore.QObject):
             "gerber_aperture_scale_factor": 1.0,
             "gerber_aperture_scale_factor": 1.0,
             "gerber_aperture_buffer_factor": 0.0,
             "gerber_aperture_buffer_factor": 0.0,
             "gerber_follow": False,
             "gerber_follow": False,
+            "gerber_buffering": "full",
+            "gerber_simplification": False,
+            "gerber_simp_tolerance": 0.0005,
 
 
             # Gerber Export
             # Gerber Export
             "gerber_exp_units": 'IN',
             "gerber_exp_units": 'IN',
@@ -917,9 +938,9 @@ class App(QtCore.QObject):
             # Excellon Options
             # Excellon Options
             "excellon_drillz": -0.0590551,
             "excellon_drillz": -0.0590551,
             "excellon_travelz": 0.0787402,
             "excellon_travelz": 0.0787402,
+            "excellon_endz": 0.5,
             "excellon_feedrate": 3.14961,
             "excellon_feedrate": 3.14961,
             "excellon_spindlespeed": None,
             "excellon_spindlespeed": None,
-            "excellon_spindledir": 'CW',
             "excellon_dwell": False,
             "excellon_dwell": False,
             "excellon_dwelltime": 1,
             "excellon_dwelltime": 1,
             "excellon_toolchange": False,
             "excellon_toolchange": False,
@@ -933,10 +954,10 @@ class App(QtCore.QObject):
             "excellon_offset": 0.0,
             "excellon_offset": 0.0,
             "excellon_toolchangexy": "0.0, 0.0",
             "excellon_toolchangexy": "0.0, 0.0",
             "excellon_startz": None,
             "excellon_startz": None,
-            "excellon_endz": 0.5,
             "excellon_feedrate_rapid": 31.4961,
             "excellon_feedrate_rapid": 31.4961,
             "excellon_z_pdepth": -0.02,
             "excellon_z_pdepth": -0.02,
             "excellon_feedrate_probe": 3.14961,
             "excellon_feedrate_probe": 3.14961,
+            "excellon_spindledir": 'CW',
             "excellon_f_plunge": False,
             "excellon_f_plunge": False,
             "excellon_f_retract": False,
             "excellon_f_retract": False,
 
 
@@ -983,10 +1004,10 @@ class App(QtCore.QObject):
             "geometry_travelz": 0.0787402,
             "geometry_travelz": 0.0787402,
             "geometry_toolchange": False,
             "geometry_toolchange": False,
             "geometry_toolchangez": 0.5,
             "geometry_toolchangez": 0.5,
+            "geometry_endz": 0.5,
             "geometry_feedrate": 3.14961,
             "geometry_feedrate": 3.14961,
             "geometry_feedrate_z": 3.14961,
             "geometry_feedrate_z": 3.14961,
             "geometry_spindlespeed": None,
             "geometry_spindlespeed": None,
-            "geometry_spindledir": 'CW',
             "geometry_dwell": False,
             "geometry_dwell": False,
             "geometry_dwelltime": 1,
             "geometry_dwelltime": 1,
             "geometry_ppname_g": 'default',
             "geometry_ppname_g": 'default',
@@ -994,11 +1015,11 @@ class App(QtCore.QObject):
             # Geometry Advanced Options
             # Geometry Advanced Options
             "geometry_toolchangexy": "0.0, 0.0",
             "geometry_toolchangexy": "0.0, 0.0",
             "geometry_startz": None,
             "geometry_startz": None,
-            "geometry_endz": 0.5,
             "geometry_feedrate_rapid": 3.14961,
             "geometry_feedrate_rapid": 3.14961,
             "geometry_extracut": False,
             "geometry_extracut": False,
             "geometry_z_pdepth": -0.02,
             "geometry_z_pdepth": -0.02,
             "geometry_f_plunge": False,
             "geometry_f_plunge": False,
+            "geometry_spindledir": 'CW',
             "geometry_feedrate_probe": 3.14961,
             "geometry_feedrate_probe": 3.14961,
             "geometry_segx": 0.0,
             "geometry_segx": 0.0,
             "geometry_segy": 0.0,
             "geometry_segy": 0.0,
@@ -1010,8 +1031,6 @@ class App(QtCore.QObject):
             "cncjob_plot": True,
             "cncjob_plot": True,
             "cncjob_plot_kind": 'all',
             "cncjob_plot_kind": 'all',
             "cncjob_annotation": True,
             "cncjob_annotation": True,
-            "cncjob_annotation_fontsize": 9,
-            "cncjob_annotation_fontcolor": '#990000',
             "cncjob_tooldia": 0.0393701,
             "cncjob_tooldia": 0.0393701,
             "cncjob_coords_type": "G90",
             "cncjob_coords_type": "G90",
             "cncjob_coords_decimals": 4,
             "cncjob_coords_decimals": 4,
@@ -1025,7 +1044,10 @@ class App(QtCore.QObject):
             # CNC Job Advanced Options
             # CNC Job Advanced Options
             "cncjob_toolchange_macro": "",
             "cncjob_toolchange_macro": "",
             "cncjob_toolchange_macro_enable": False,
             "cncjob_toolchange_macro_enable": False,
+            "cncjob_annotation_fontsize": 9,
+            "cncjob_annotation_fontcolor": '#990000',
 
 
+            # NCC Tool
             "tools_ncctools": "0.0393701, 0.019685",
             "tools_ncctools": "0.0393701, 0.019685",
             "tools_nccorder": 'rev',
             "tools_nccorder": 'rev',
             "tools_nccoverlap": 0.015748,
             "tools_nccoverlap": 0.015748,
@@ -1044,6 +1066,7 @@ class App(QtCore.QObject):
             "tools_ncctipdia": 0.00393701,
             "tools_ncctipdia": 0.00393701,
             "tools_ncctipangle": 30,
             "tools_ncctipangle": 30,
 
 
+            # Cutout Tool
             "tools_cutouttooldia": 0.0944882,
             "tools_cutouttooldia": 0.0944882,
             "tools_cutoutkind": "single",
             "tools_cutoutkind": "single",
             "tools_cutoutmargin": 0.00393701,
             "tools_cutoutmargin": 0.00393701,
@@ -1051,6 +1074,7 @@ class App(QtCore.QObject):
             "tools_gaps_ff": "4",
             "tools_gaps_ff": "4",
             "tools_cutout_convexshape": False,
             "tools_cutout_convexshape": False,
 
 
+            # Paint Tool
             "tools_painttooldia": 0.023622,
             "tools_painttooldia": 0.023622,
             "tools_paintorder": 'rev',
             "tools_paintorder": 'rev',
             "tools_paintoverlap": 0.015748,
             "tools_paintoverlap": 0.015748,
@@ -1061,14 +1085,18 @@ class App(QtCore.QObject):
             "tools_paintcontour": True,
             "tools_paintcontour": True,
             "tools_paint_plotting": 'normal',
             "tools_paint_plotting": 'normal',
 
 
+            # 2-Sided Tool
             "tools_2sided_mirror_axis": "X",
             "tools_2sided_mirror_axis": "X",
             "tools_2sided_axis_loc": "point",
             "tools_2sided_axis_loc": "point",
             "tools_2sided_drilldia": 0.0393701,
             "tools_2sided_drilldia": 0.0393701,
 
 
+            # Film Tool
             "tools_film_type": 'neg',
             "tools_film_type": 'neg',
             "tools_film_boundary": 0.0393701,
             "tools_film_boundary": 0.0393701,
             "tools_film_scale": 0,
             "tools_film_scale": 0,
+            "tools_film_color": '#000000',
 
 
+            # Panel Tool
             "tools_panelize_spacing_columns": 0,
             "tools_panelize_spacing_columns": 0,
             "tools_panelize_spacing_rows": 0,
             "tools_panelize_spacing_rows": 0,
             "tools_panelize_columns": 1,
             "tools_panelize_columns": 1,
@@ -1078,6 +1106,7 @@ class App(QtCore.QObject):
             "tools_panelize_constrainy": 0.0,
             "tools_panelize_constrainy": 0.0,
             "tools_panelize_panel_type": 'gerber',
             "tools_panelize_panel_type": 'gerber',
 
 
+            # Calculators Tool
             "tools_calc_vshape_tip_dia": 0.007874,
             "tools_calc_vshape_tip_dia": 0.007874,
             "tools_calc_vshape_tip_angle": 30,
             "tools_calc_vshape_tip_angle": 30,
             "tools_calc_vshape_cut_z": 0.000787,
             "tools_calc_vshape_cut_z": 0.000787,
@@ -1086,6 +1115,7 @@ class App(QtCore.QObject):
             "tools_calc_electro_cdensity": 13.0,
             "tools_calc_electro_cdensity": 13.0,
             "tools_calc_electro_growth": 10.0,
             "tools_calc_electro_growth": 10.0,
 
 
+            # Transform Tool
             "tools_transform_rotate": 90,
             "tools_transform_rotate": 90,
             "tools_transform_skew_x": 0.0,
             "tools_transform_skew_x": 0.0,
             "tools_transform_skew_y": 0.0,
             "tools_transform_skew_y": 0.0,
@@ -1098,6 +1128,7 @@ class App(QtCore.QObject):
             "tools_transform_mirror_reference": False,
             "tools_transform_mirror_reference": False,
             "tools_transform_mirror_point": (0, 0),
             "tools_transform_mirror_point": (0, 0),
 
 
+            # SolderPaste Tool
             "tools_solderpaste_tools": "0.0393701, 0.011811",
             "tools_solderpaste_tools": "0.0393701, 0.011811",
             "tools_solderpaste_new": 0.011811,
             "tools_solderpaste_new": 0.011811,
             "tools_solderpaste_z_start": 0.00019685039,
             "tools_solderpaste_z_start": 0.00019685039,
@@ -1115,6 +1146,7 @@ class App(QtCore.QObject):
             "tools_solderpaste_dwellrev": 1,
             "tools_solderpaste_dwellrev": 1,
             "tools_solderpaste_pp": 'Paste_1',
             "tools_solderpaste_pp": 'Paste_1',
 
 
+            # Subtract Tool
             "tools_sub_close_paths": True,
             "tools_sub_close_paths": True,
 
 
             # file associations
             # file associations
@@ -1204,9 +1236,9 @@ class App(QtCore.QObject):
 
 
             "excellon_drillz": self.ui.excellon_options_form.excellon_opt_group.cutz_entry,
             "excellon_drillz": self.ui.excellon_options_form.excellon_opt_group.cutz_entry,
             "excellon_travelz": self.ui.excellon_options_form.excellon_opt_group.travelz_entry,
             "excellon_travelz": self.ui.excellon_options_form.excellon_opt_group.travelz_entry,
+            "excellon_endz": self.ui.excellon_options_form.excellon_opt_group.eendz_entry,
             "excellon_feedrate": self.ui.excellon_options_form.excellon_opt_group.feedrate_entry,
             "excellon_feedrate": self.ui.excellon_options_form.excellon_opt_group.feedrate_entry,
             "excellon_spindlespeed": self.ui.excellon_options_form.excellon_opt_group.spindlespeed_entry,
             "excellon_spindlespeed": self.ui.excellon_options_form.excellon_opt_group.spindlespeed_entry,
-            "excellon_spindledir": self.ui.excellon_options_form.excellon_opt_group.spindledir_radio,
             "excellon_dwell": self.ui.excellon_options_form.excellon_opt_group.dwell_cb,
             "excellon_dwell": self.ui.excellon_options_form.excellon_opt_group.dwell_cb,
             "excellon_dwelltime": self.ui.excellon_options_form.excellon_opt_group.dwelltime_entry,
             "excellon_dwelltime": self.ui.excellon_options_form.excellon_opt_group.dwelltime_entry,
             "excellon_toolchange": self.ui.excellon_options_form.excellon_opt_group.toolchange_cb,
             "excellon_toolchange": self.ui.excellon_options_form.excellon_opt_group.toolchange_cb,
@@ -1218,7 +1250,7 @@ class App(QtCore.QObject):
             "excellon_toolchangexy": self.ui.excellon_options_form.excellon_adv_opt_group.toolchangexy_entry,
             "excellon_toolchangexy": self.ui.excellon_options_form.excellon_adv_opt_group.toolchangexy_entry,
             "excellon_f_plunge": self.ui.excellon_options_form.excellon_adv_opt_group.fplunge_cb,
             "excellon_f_plunge": self.ui.excellon_options_form.excellon_adv_opt_group.fplunge_cb,
             "excellon_startz": self.ui.excellon_options_form.excellon_adv_opt_group.estartz_entry,
             "excellon_startz": self.ui.excellon_options_form.excellon_adv_opt_group.estartz_entry,
-            "excellon_endz": self.ui.excellon_options_form.excellon_adv_opt_group.eendz_entry,
+            "excellon_spindledir": self.ui.excellon_options_form.excellon_adv_opt_group.spindledir_radio,
 
 
             "geometry_plot": self.ui.geometry_options_form.geometry_gen_group.plot_cb,
             "geometry_plot": self.ui.geometry_options_form.geometry_gen_group.plot_cb,
             "geometry_cnctooldia": self.ui.geometry_options_form.geometry_gen_group.cnctooldia_entry,
             "geometry_cnctooldia": self.ui.geometry_options_form.geometry_gen_group.cnctooldia_entry,
@@ -1228,12 +1260,12 @@ class App(QtCore.QObject):
             "geometry_feedrate": self.ui.geometry_options_form.geometry_opt_group.cncfeedrate_entry,
             "geometry_feedrate": self.ui.geometry_options_form.geometry_opt_group.cncfeedrate_entry,
             "geometry_feedrate_z": self.ui.geometry_options_form.geometry_opt_group.cncplunge_entry,
             "geometry_feedrate_z": self.ui.geometry_options_form.geometry_opt_group.cncplunge_entry,
             "geometry_spindlespeed": self.ui.geometry_options_form.geometry_opt_group.cncspindlespeed_entry,
             "geometry_spindlespeed": self.ui.geometry_options_form.geometry_opt_group.cncspindlespeed_entry,
-            "geometry_spindledir": self.ui.geometry_options_form.geometry_opt_group.spindledir_radio,
             "geometry_dwell": self.ui.geometry_options_form.geometry_opt_group.dwell_cb,
             "geometry_dwell": self.ui.geometry_options_form.geometry_opt_group.dwell_cb,
             "geometry_dwelltime": self.ui.geometry_options_form.geometry_opt_group.dwelltime_entry,
             "geometry_dwelltime": self.ui.geometry_options_form.geometry_opt_group.dwelltime_entry,
             "geometry_ppname_g": self.ui.geometry_options_form.geometry_opt_group.pp_geometry_name_cb,
             "geometry_ppname_g": self.ui.geometry_options_form.geometry_opt_group.pp_geometry_name_cb,
             "geometry_toolchange": self.ui.geometry_options_form.geometry_opt_group.toolchange_cb,
             "geometry_toolchange": self.ui.geometry_options_form.geometry_opt_group.toolchange_cb,
             "geometry_toolchangez": self.ui.geometry_options_form.geometry_opt_group.toolchangez_entry,
             "geometry_toolchangez": self.ui.geometry_options_form.geometry_opt_group.toolchangez_entry,
+            "geometry_endz": self.ui.geometry_options_form.geometry_opt_group.gendz_entry,
             "geometry_depthperpass": self.ui.geometry_options_form.geometry_opt_group.depthperpass_entry,
             "geometry_depthperpass": self.ui.geometry_options_form.geometry_opt_group.depthperpass_entry,
             "geometry_multidepth": self.ui.geometry_options_form.geometry_opt_group.multidepth_cb,
             "geometry_multidepth": self.ui.geometry_options_form.geometry_opt_group.multidepth_cb,
 
 
@@ -1241,9 +1273,9 @@ class App(QtCore.QObject):
             "geometry_segy": self.ui.geometry_options_form.geometry_adv_opt_group.segy_entry,
             "geometry_segy": self.ui.geometry_options_form.geometry_adv_opt_group.segy_entry,
             "geometry_feedrate_rapid": self.ui.geometry_options_form.geometry_adv_opt_group.cncfeedrate_rapid_entry,
             "geometry_feedrate_rapid": self.ui.geometry_options_form.geometry_adv_opt_group.cncfeedrate_rapid_entry,
             "geometry_f_plunge": self.ui.geometry_options_form.geometry_adv_opt_group.fplunge_cb,
             "geometry_f_plunge": self.ui.geometry_options_form.geometry_adv_opt_group.fplunge_cb,
+            "geometry_spindledir": self.ui.geometry_options_form.geometry_adv_opt_group.spindledir_radio,
             "geometry_toolchangexy": self.ui.geometry_options_form.geometry_adv_opt_group.toolchangexy_entry,
             "geometry_toolchangexy": self.ui.geometry_options_form.geometry_adv_opt_group.toolchangexy_entry,
             "geometry_startz": self.ui.geometry_options_form.geometry_adv_opt_group.gstartz_entry,
             "geometry_startz": self.ui.geometry_options_form.geometry_adv_opt_group.gstartz_entry,
-            "geometry_endz": self.ui.geometry_options_form.geometry_adv_opt_group.gendz_entry,
             "geometry_extracut": self.ui.geometry_options_form.geometry_adv_opt_group.extracut_cb,
             "geometry_extracut": self.ui.geometry_options_form.geometry_adv_opt_group.extracut_cb,
 
 
             "cncjob_plot": self.ui.cncjob_options_form.cncjob_gen_group.plot_cb,
             "cncjob_plot": self.ui.cncjob_options_form.cncjob_gen_group.plot_cb,
@@ -1487,10 +1519,17 @@ class App(QtCore.QObject):
             "background-color:%s" % str(self.defaults['global_proj_item_dis_color'])[:7])
             "background-color:%s" % str(self.defaults['global_proj_item_dis_color'])[:7])
 
 
         # Init the Annotation CNC Job color
         # Init the Annotation CNC Job color
-        self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontcolor_entry.set_value(
+        self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_entry.set_value(
             self.defaults['cncjob_annotation_fontcolor'])
             self.defaults['cncjob_annotation_fontcolor'])
-        self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontcolor_button.setStyleSheet(
+        self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['cncjob_annotation_fontcolor'])[:7])
             "background-color:%s" % str(self.defaults['cncjob_annotation_fontcolor'])[:7])
+
+        # Init the Tool Film color
+        self.ui.tools_defaults_form.tools_film_group.film_color_entry.set_value(
+            self.defaults['tools_film_color'])
+        self.ui.tools_defaults_form.tools_film_group.film_color_button.setStyleSheet(
+            "background-color:%s" % str(self.defaults['tools_film_color'])[:7])
+
         # ### End of Data ####
         # ### End of Data ####
 
 
         # ###############################################
         # ###############################################
@@ -1671,6 +1710,9 @@ class App(QtCore.QObject):
         self.ui.menuhelp_about.triggered.connect(self.on_about)
         self.ui.menuhelp_about.triggered.connect(self.on_about)
         self.ui.menuhelp_home.triggered.connect(lambda: webbrowser.open(self.app_url))
         self.ui.menuhelp_home.triggered.connect(lambda: webbrowser.open(self.app_url))
         self.ui.menuhelp_manual.triggered.connect(lambda: webbrowser.open(self.manual_url))
         self.ui.menuhelp_manual.triggered.connect(lambda: webbrowser.open(self.manual_url))
+        self.ui.menuhelp_report_bug.triggered.connect(lambda: webbrowser.open(self.bug_report_url))
+        self.ui.menuhelp_exc_spec.triggered.connect(lambda: webbrowser.open(self.excellon_spec_url))
+        self.ui.menuhelp_gerber_spec.triggered.connect(lambda: webbrowser.open(self.gerber_spec_url))
         self.ui.menuhelp_videohelp.triggered.connect(lambda: webbrowser.open(self.video_url))
         self.ui.menuhelp_videohelp.triggered.connect(lambda: webbrowser.open(self.video_url))
         self.ui.menuhelp_shortcut_list.triggered.connect(self.on_shortcut_list)
         self.ui.menuhelp_shortcut_list.triggered.connect(self.on_shortcut_list)
 
 
@@ -1809,11 +1851,17 @@ class App(QtCore.QObject):
         # ########## CNC Job related signals #############
         # ########## CNC Job related signals #############
         self.ui.cncjob_defaults_form.cncjob_adv_opt_group.tc_variable_combo.currentIndexChanged[str].connect(
         self.ui.cncjob_defaults_form.cncjob_adv_opt_group.tc_variable_combo.currentIndexChanged[str].connect(
             self.on_cnc_custom_parameters)
             self.on_cnc_custom_parameters)
-        self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontcolor_entry.editingFinished.connect(
+        self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_entry.editingFinished.connect(
             self.on_annotation_fontcolor_entry)
             self.on_annotation_fontcolor_entry)
-        self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontcolor_button.clicked.connect(
+        self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_button.clicked.connect(
             self.on_annotation_fontcolor_button)
             self.on_annotation_fontcolor_button)
 
 
+        # ########## Tools related signals #############
+        self.ui.tools_defaults_form.tools_film_group.film_color_entry.editingFinished.connect(
+            self.on_film_color_entry)
+        self.ui.tools_defaults_form.tools_film_group.film_color_button.clicked.connect(
+            self.on_film_color_button)
+
         # ########## Modify G-CODE Plot Area TAB ###########
         # ########## Modify G-CODE Plot Area TAB ###########
         self.ui.code_editor.textChanged.connect(self.handleTextChanged)
         self.ui.code_editor.textChanged.connect(self.handleTextChanged)
         self.ui.buttonOpen.clicked.connect(self.handleOpen)
         self.ui.buttonOpen.clicked.connect(self.handleOpen)
@@ -1830,7 +1878,7 @@ class App(QtCore.QObject):
         self.collection.view.activated.connect(self.on_row_activated)
         self.collection.view.activated.connect(self.on_row_activated)
 
 
         # Monitor the checkbox from the Application Defaults Tab and show the TCL shell or not depending on it's value
         # Monitor the checkbox from the Application Defaults Tab and show the TCL shell or not depending on it's value
-        self.ui.general_defaults_form.general_app_group.shell_startup_cb.clicked.connect(self.on_toggle_shell)
+        self.ui.general_defaults_form.general_gui_set_group.shell_startup_cb.clicked.connect(self.on_toggle_shell)
 
 
         # Make sure that when the Excellon loading parameters are changed, the change is reflected in the
         # Make sure that when the Excellon loading parameters are changed, the change is reflected in the
         # Export Excellon parameters.
         # Export Excellon parameters.
@@ -1900,27 +1948,13 @@ class App(QtCore.QObject):
                                   'mirror', 'ncc',
                                   'mirror', 'ncc',
                                   'ncc_clear', 'ncr', 'new', 'new_geometry', 'non_copper_regions', 'offset',
                                   'ncc_clear', 'ncr', 'new', 'new_geometry', 'non_copper_regions', 'offset',
                                   'open_excellon', 'open_gcode', 'open_gerber', 'open_project', 'options', 'paint',
                                   'open_excellon', 'open_gcode', 'open_gerber', 'open_project', 'options', 'paint',
-                                  'pan', 'panel', 'panelize', 'plot', 'save', 'save_project', 'save_sys', 'scale',
+                                  'pan', 'panel', 'panelize', 'plot_all', 'plot_objects', 'save', 'save_project',
+                                  'save_sys', 'scale',
                                   'set_active', 'set_sys', 'setsys', 'skew', 'subtract_poly', 'subtract_rectangle',
                                   'set_active', 'set_sys', 'setsys', 'skew', 'subtract_poly', 'subtract_rectangle',
                                   'version', 'write_gcode'
                                   'version', 'write_gcode'
                                   ]
                                   ]
 
 
-        self.ordinary_keywords = ['all', 'angle_x', 'angle_y', 'axis', 'axisoffset', 'box', 'center_x', 'center_y',
-                                  'columns', 'combine', 'connect', 'contour', 'depthperpass', 'dia', 'diatol', 'dist',
-                                  'drilled_dias', 'drillz', 'pp',
-                                  'endz', 'extracut', 'factor', 'False', 'false', 'feedrate', 'feedrate_rapid',
-                                  'filename', 'follow', 'gaps', 'gapsize', 'grid', 'gridoffset', 'gridoffsetx',
-                                  'gridoffsety', 'gridx', 'gridy', 'has_offset', 'holes', 'margin', 'method',
-                                  'milled_dias',
-                                  'minoffset', 'multidepth', 'name', 'offset', 'opt_type', 'order', 'outname',
-                                  'overlap', 'passes', 'postamble', 'ppname_e', 'ppname_g', 'preamble', 'radius', 'ref',
-                                  'rest', 'rows', 'scale_factor', 'spacing_columns', 'spacing_rows', 'spindlespeed',
-                                  'toolchange', 'toolchangez', 'tooldia', 'tools', 'travelz', 'True', 'true', 'type',
-                                  'use_threads', 'value', 'x', 'x0', 'x1', 'y', 'y0', 'y1', 'z_cut', 'z_move',
-                                  'default', 'feedrate_z', 'grbl_11', 'grbl_laser', 'hpgl', 'line_xyz', 'marlin',
-                                  'Paste_1', 'Repetier', 'Toolchange_Custom', 'Roland_MDX_20', 'Toolchange_manual',
-                                  'Toolchange_Probe_MACH3', 'dwell', 'dwelltime', 'toolchange_xy'
-                                  ]
+        self.ordinary_keywords = self.defaults["global_autocomplete_keywords"]
 
 
         self.tcl_keywords = [
         self.tcl_keywords = [
             'after', 'append', 'apply', 'argc', 'argv', 'argv0', 'array', 'attemptckalloc', 'attemptckrealloc',
             'after', 'append', 'apply', 'argc', 'argv', 'argv0', 'array', 'attemptckalloc', 'attemptckrealloc',
@@ -2255,6 +2289,10 @@ class App(QtCore.QObject):
         # Variable to store the GCODE that was edited
         # Variable to store the GCODE that was edited
         self.gcode_edited = ""
         self.gcode_edited = ""
 
 
+        # reference for the self.ui.code_editor
+        self.reference_code_editor = None
+        self.script_code = ''
+
         # if Preferences are changed in the Edit -> Preferences tab the value will be set to True
         # if Preferences are changed in the Edit -> Preferences tab the value will be set to True
         self.preferences_changed_flag = False
         self.preferences_changed_flag = False
 
 
@@ -3064,8 +3102,8 @@ class App(QtCore.QObject):
         result = self.exec_command_test(text, False)
         result = self.exec_command_test(text, False)
 
 
         # MS: added this method call so the geometry is updated once the TCL command is executed
         # MS: added this method call so the geometry is updated once the TCL command is executed
-        if no_plot is None:
-            self.plot_all()
+        # if no_plot is None:
+        #     self.plot_all()
 
 
         return result
         return result
 
 
@@ -5554,8 +5592,8 @@ class App(QtCore.QObject):
 
 
     def on_annotation_fontcolor_entry(self):
     def on_annotation_fontcolor_entry(self):
         self.defaults['cncjob_annotation_fontcolor'] = \
         self.defaults['cncjob_annotation_fontcolor'] = \
-            self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontcolor_entry.get_value()
-        self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontcolor_button.setStyleSheet(
+            self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_entry.get_value()
+        self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_button.setStyleSheet(
             "background-color:%s" % str(self.defaults['cncjob_annotation_fontcolor']))
             "background-color:%s" % str(self.defaults['cncjob_annotation_fontcolor']))
 
 
     def on_annotation_fontcolor_button(self):
     def on_annotation_fontcolor_button(self):
@@ -5567,12 +5605,38 @@ class App(QtCore.QObject):
         if annotation_color.isValid() is False:
         if annotation_color.isValid() is False:
             return
             return
 
 
-        self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontcolor_button.setStyleSheet(
+        self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_button.setStyleSheet(
             "background-color:%s" % str(annotation_color.name()))
             "background-color:%s" % str(annotation_color.name()))
 
 
         new_val_sel = str(annotation_color.name())
         new_val_sel = str(annotation_color.name())
-        self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontcolor_entry.set_value(new_val_sel)
-        self.defaults['global_proj_item_dis_color'] = new_val_sel
+        self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_entry.set_value(new_val_sel)
+        self.defaults['cncjob_annotation_fontcolor'] = new_val_sel
+
+    def on_film_color_entry(self):
+        self.defaults['tools_film_color'] = \
+            self.ui.tools_defaults_form.tools_film_group.film_color_entry.get_value()
+        self.ui.tools_defaults_form.tools_film_group.film_color_button.setStyleSheet(
+            "background-color:%s" % str(self.defaults['tools_film_color']))
+
+    def on_film_color_button(self):
+        current_color = QtGui.QColor(self.defaults['tools_film_color'])
+
+        c_dialog = QtWidgets.QColorDialog()
+        film_color = c_dialog.getColor(initial=current_color)
+
+        if film_color.isValid() is False:
+            return
+
+        # if new color is different then mark that the Preferences are changed
+        if film_color != current_color:
+            self.on_preferences_edited()
+
+        self.ui.tools_defaults_form.tools_film_group.film_color_button.setStyleSheet(
+            "background-color:%s" % str(film_color.name()))
+
+        new_val_sel = str(film_color.name())
+        self.ui.tools_defaults_form.tools_film_group.film_color_entry.set_value(new_val_sel)
+        self.defaults['tools_film_color'] = new_val_sel
 
 
     def on_splash_changed(self, state):
     def on_splash_changed(self, state):
         settings = QSettings("Open Source", "FlatCAM")
         settings = QSettings("Open Source", "FlatCAM")
@@ -5915,11 +5979,11 @@ class App(QtCore.QObject):
         if self.ui.shell_dock.isHidden():
         if self.ui.shell_dock.isHidden():
             self.ui.shell_dock.show()
             self.ui.shell_dock.show()
 
 
-        script_code = self.ui.code_editor.toPlainText()
+        self.script_code = deepcopy(self.ui.code_editor.toPlainText())
         # self.shell._sysShell.exec_command(script_code)
         # self.shell._sysShell.exec_command(script_code)
 
 
         old_line = ''
         old_line = ''
-        for tcl_command_line in script_code.splitlines():
+        for tcl_command_line in self.script_code.splitlines():
             # do not process lines starting with '#' = comment and empty lines
             # do not process lines starting with '#' = comment and empty lines
             if not tcl_command_line.startswith('#') and tcl_command_line != '':
             if not tcl_command_line.startswith('#') and tcl_command_line != '':
                 # id FlatCAM is run in Windows then replace all the slashes with
                 # id FlatCAM is run in Windows then replace all the slashes with
@@ -5942,17 +6006,16 @@ class App(QtCore.QObject):
                         self.shell.append_output(result + '\n')
                         self.shell.append_output(result + '\n')
 
 
                     old_line = ''
                     old_line = ''
-                except tk.TclError as e:
+                except tk.TclError:
                     old_line = old_line + tcl_command_line + '\n'
                     old_line = old_line + tcl_command_line + '\n'
+                except Exception as e:
+                    log.debug("App.handleRunCode() --> %s" % str(e))
 
 
         if old_line != '':
         if old_line != '':
             # it means that the script finished with an error
             # it means that the script finished with an error
             result = self.tcl.eval("set errorInfo")
             result = self.tcl.eval("set errorInfo")
             self.log.error("Exec command Exception: %s" % (result + '\n'))
             self.log.error("Exec command Exception: %s" % (result + '\n'))
             self.shell.append_error('ERROR: ' + result + '\n')
             self.shell.append_error('ERROR: ' + result + '\n')
-        else:
-            # success! plot all objects
-            self.plot_all()
 
 
         self.shell.close_proccessing()
         self.shell.close_proccessing()
 
 
@@ -7522,7 +7585,7 @@ class App(QtCore.QObject):
         self.inform.emit('[success] %s...' %
         self.inform.emit('[success] %s...' %
                          _("New Project created"))
                          _("New Project created"))
 
 
-    def on_file_new(self):
+    def on_file_new(self, cli=None):
         """
         """
         Callback for menu item File->New. Returns the application to its
         Callback for menu item File->New. Returns the application to its
         startup state. This method is thread-safe.
         startup state. This method is thread-safe.
@@ -7582,15 +7645,16 @@ class App(QtCore.QObject):
         # Init Tools
         # Init Tools
         self.init_tools()
         self.init_tools()
 
 
-        # Close any Tabs opened in the Plot Tab Area section
-        for index in range(self.ui.plot_tab_area.count()):
-            self.ui.plot_tab_area.closeTab(index)
-            # for whatever reason previous command does not close the last tab so I do it manually
-        self.ui.plot_tab_area.closeTab(0)
+        if cli is None:
+            # Close any Tabs opened in the Plot Tab Area section
+            for index in range(self.ui.plot_tab_area.count()):
+                self.ui.plot_tab_area.closeTab(index)
+                # for whatever reason previous command does not close the last tab so I do it manually
+            self.ui.plot_tab_area.closeTab(0)
 
 
-        # # And then add again the Plot Area
-        self.ui.plot_tab_area.addTab(self.ui.plot_tab, "Plot Area")
-        self.ui.plot_tab_area.protectTab(0)
+            # # And then add again the Plot Area
+            self.ui.plot_tab_area.addTab(self.ui.plot_tab, "Plot Area")
+            self.ui.plot_tab_area.protectTab(0)
 
 
         # take the focus of the Notebook on Project Tab.
         # take the focus of the Notebook on Project Tab.
         self.ui.notebook.setCurrentWidget(self.ui.project_tab)
         self.ui.notebook.setCurrentWidget(self.ui.project_tab)
@@ -8201,6 +8265,9 @@ class App(QtCore.QObject):
         self.ui.code_editor.completer_enable = False
         self.ui.code_editor.completer_enable = False
         self.ui.buttonRun.hide()
         self.ui.buttonRun.hide()
 
 
+        # make sure to keep a reference to the code editor
+        self.reference_code_editor = self.ui.code_editor
+
         # Switch plot_area to CNCJob tab
         # Switch plot_area to CNCJob tab
         self.ui.plot_tab_area.setCurrentWidget(self.ui.cncjob_tab)
         self.ui.plot_tab_area.setCurrentWidget(self.ui.cncjob_tab)
 
 
@@ -8219,20 +8286,37 @@ class App(QtCore.QObject):
 
 
         if obj.kind == 'gerber':
         if obj.kind == 'gerber':
             flt = "Gerber Files (*.GBR);;All Files (*.*)"
             flt = "Gerber Files (*.GBR);;All Files (*.*)"
-        else:
+        elif obj.kind == 'excellon':
             flt = "Excellon Files (*.DRL);;All Files (*.*)"
             flt = "Excellon Files (*.DRL);;All Files (*.*)"
+        elif obj.kind == 'cncjob':
+            "GCode Files (*.NC);;All Files (*.*)"
+        else:
+            flt = "All Files (*.*)"
 
 
         self.init_code_editor(name=_("Source Editor"))
         self.init_code_editor(name=_("Source Editor"))
         self.ui.buttonOpen.clicked.connect(lambda: self.handleOpen(filt=flt))
         self.ui.buttonOpen.clicked.connect(lambda: self.handleOpen(filt=flt))
         self.ui.buttonSave.clicked.connect(lambda: self.handleSaveGCode(filt=flt))
         self.ui.buttonSave.clicked.connect(lambda: self.handleSaveGCode(filt=flt))
 
 
         # then append the text from GCode to the text editor
         # then append the text from GCode to the text editor
-        try:
-            file = StringIO(obj.source_file)
-        except AttributeError:
-            self.inform.emit('[WARNING_NOTCL] %s' %
-                             _("There is no selected object for which to see it's source file code."))
-            return 'fail'
+        if obj.kind == 'cncjob':
+            try:
+                file = obj.export_gcode(
+                    preamble=self.defaults["cncjob_prepend"],
+                    postamble=self.defaults["cncjob_append"],
+                    to_file=True)
+                if file == 'fail':
+                    return 'fail'
+            except AttributeError:
+                self.inform.emit('[WARNING_NOTCL] %s' %
+                                 _("There is no selected object for which to see it's source file code."))
+                return 'fail'
+        else:
+            try:
+                file = StringIO(obj.source_file)
+            except AttributeError:
+                self.inform.emit('[WARNING_NOTCL] %s' %
+                                 _("There is no selected object for which to see it's source file code."))
+                return 'fail'
 
 
         self.ui.cncjob_frame.hide()
         self.ui.cncjob_frame.hide()
         try:
         try:
@@ -8289,6 +8373,10 @@ class App(QtCore.QObject):
         self.ui.buttonOpen.clicked.connect(lambda: self.handleOpen(filt=flt))
         self.ui.buttonOpen.clicked.connect(lambda: self.handleOpen(filt=flt))
         self.ui.buttonSave.clicked.connect(lambda: self.handleSaveGCode(filt=flt))
         self.ui.buttonSave.clicked.connect(lambda: self.handleSaveGCode(filt=flt))
         self.ui.buttonRun.show()
         self.ui.buttonRun.show()
+        try:
+            self.ui.buttonRun.clicked.disconnect(self.handleRunCode)
+        except TypeError:
+            pass
         self.ui.buttonRun.clicked.connect(self.handleRunCode)
         self.ui.buttonRun.clicked.connect(self.handleRunCode)
 
 
         self.handleTextChanged()
         self.handleTextChanged()
@@ -8556,8 +8644,6 @@ class App(QtCore.QObject):
         def make_negative_film():
         def make_negative_film():
             exported_svg = obj.export_svg(scale_factor=scale_factor)
             exported_svg = obj.export_svg(scale_factor=scale_factor)
 
 
-            self.progress.emit(40)
-
             # Determine bounding area for svg export
             # Determine bounding area for svg export
             bounds = box.bounds()
             bounds = box.bounds()
             size = box.size()
             size = box.size()
@@ -8583,8 +8669,6 @@ class App(QtCore.QObject):
             svg_header += '<g transform="scale(1,-1)">'
             svg_header += '<g transform="scale(1,-1)">'
             svg_footer = '</g> </svg>'
             svg_footer = '</g> </svg>'
 
 
-            self.progress.emit(60)
-
             # Change the attributes of the exported SVG
             # Change the attributes of the exported SVG
             # We don't need stroke-width - wrong, we do when we have lines with certain width
             # We don't need stroke-width - wrong, we do when we have lines with certain width
             # We set opacity to maximum
             # We set opacity to maximum
@@ -8613,7 +8697,6 @@ class App(QtCore.QObject):
             exported_svg = ET.tostring(root)
             exported_svg = ET.tostring(root)
 
 
             svg_elem = svg_header + str(exported_svg) + svg_footer
             svg_elem = svg_header + str(exported_svg) + svg_footer
-            self.progress.emit(80)
 
 
             # Parse the xml through a xml parser just to add line feeds
             # Parse the xml through a xml parser just to add line feeds
             # and to make it look more pretty for the output
             # and to make it look more pretty for the output
@@ -8627,7 +8710,6 @@ class App(QtCore.QObject):
                                    "Most likely another app is holding the file open and not accessible."))
                                    "Most likely another app is holding the file open and not accessible."))
                 return 'fail'
                 return 'fail'
 
 
-            self.progress.emit(100)
             if self.defaults["global_open_style"] is False:
             if self.defaults["global_open_style"] is False:
                 self.file_opened.emit("SVG", filename)
                 self.file_opened.emit("SVG", filename)
             self.file_saved.emit("SVG", filename)
             self.file_saved.emit("SVG", filename)
@@ -8649,7 +8731,7 @@ class App(QtCore.QObject):
         else:
         else:
             make_negative_film()
             make_negative_film()
 
 
-    def export_svg_black(self, obj_name, box_name, filename, scale_factor=0.00, use_thread=True):
+    def export_svg_positive(self, obj_name, box_name, filename, scale_factor=0.00, use_thread=True):
         """
         """
         Exports a Geometry Object to an SVG file in positive black.
         Exports a Geometry Object to an SVG file in positive black.
 
 
@@ -8660,7 +8742,7 @@ class App(QtCore.QObject):
         :param use_thread: if to be run in a separate thread; boolean
         :param use_thread: if to be run in a separate thread; boolean
         :return:
         :return:
         """
         """
-        self.report_usage("export_svg_black()")
+        self.report_usage("export_svg_positive()")
 
 
         if filename is None:
         if filename is None:
             filename = self.defaults["global_last_save_folder"]
             filename = self.defaults["global_last_save_folder"]
@@ -8684,7 +8766,7 @@ class App(QtCore.QObject):
                              (_("No object Box. Using instead"), obj))
                              (_("No object Box. Using instead"), obj))
             box = obj
             box = obj
 
 
-        def make_black_film():
+        def make_positive_film():
             exported_svg = obj.export_svg(scale_factor=scale_factor)
             exported_svg = obj.export_svg(scale_factor=scale_factor)
 
 
             self.progress.emit(40)
             self.progress.emit(40)
@@ -8695,9 +8777,9 @@ class App(QtCore.QObject):
             # We set the colour to WHITE
             # We set the colour to WHITE
             root = ET.fromstring(exported_svg)
             root = ET.fromstring(exported_svg)
             for child in root:
             for child in root:
-                child.set('fill', '#000000')
+                child.set('fill', str(self.defaults['tools_film_color']))
                 child.set('opacity', '1.0')
                 child.set('opacity', '1.0')
-                child.set('stroke', '#000000')
+                child.set('stroke', str(self.defaults['tools_film_color']))
 
 
             exported_svg = ET.tostring(root)
             exported_svg = ET.tostring(root)
 
 
@@ -8765,7 +8847,7 @@ class App(QtCore.QObject):
 
 
             def job_thread_film(app_obj):
             def job_thread_film(app_obj):
                 try:
                 try:
-                    make_black_film()
+                    make_positive_film()
                 except Exception as e:
                 except Exception as e:
                     proc.done()
                     proc.done()
                     return
                     return
@@ -8773,7 +8855,7 @@ class App(QtCore.QObject):
 
 
             self.worker_task.emit({'fcn': job_thread_film, 'params': [self]})
             self.worker_task.emit({'fcn': job_thread_film, 'params': [self]})
         else:
         else:
-            make_black_film()
+            make_positive_film()
 
 
     def save_source_file(self, obj_name, filename, use_thread=True):
     def save_source_file(self, obj_name, filename, use_thread=True):
         """
         """
@@ -9375,7 +9457,7 @@ class App(QtCore.QObject):
             self.inform.emit('[success] %s: %s' %
             self.inform.emit('[success] %s: %s' %
                              (_("Opened"), filename))
                              (_("Opened"), filename))
 
 
-    def open_excellon(self, filename, outname=None):
+    def open_excellon(self, filename, outname=None, plot=True):
         """
         """
         Opens an Excellon file, parses it and creates a new object for
         Opens an Excellon file, parses it and creates a new object for
         it in the program. Thread-safe.
         it in the program. Thread-safe.
@@ -9429,7 +9511,7 @@ class App(QtCore.QObject):
 
 
             # Object name
             # Object name
             name = outname or filename.split('/')[-1].split('\\')[-1]
             name = outname or filename.split('/')[-1].split('\\')[-1]
-            ret_val = self.new_object("excellon", name, obj_init, autoselected=False)
+            ret_val = self.new_object("excellon", name, obj_init, autoselected=False, plot=plot)
             if ret_val == 'fail':
             if ret_val == 'fail':
                 self.inform.emit('[ERROR_NOTCL] %s' %
                 self.inform.emit('[ERROR_NOTCL] %s' %
                                  _('Open Excellon file failed. Probable not an Excellon file.'))
                                  _('Open Excellon file failed. Probable not an Excellon file.'))
@@ -9442,7 +9524,7 @@ class App(QtCore.QObject):
             self.inform.emit('[success] %s: %s' %
             self.inform.emit('[success] %s: %s' %
                              (_("Opened"), filename))
                              (_("Opened"), filename))
 
 
-    def open_gcode(self, filename, outname=None):
+    def open_gcode(self, filename, outname=None, plot=True):
         """
         """
         Opens a G-gcode file, parses it and creates a new object for
         Opens a G-gcode file, parses it and creates a new object for
         it in the program. Thread-safe.
         it in the program. Thread-safe.
@@ -9494,7 +9576,7 @@ class App(QtCore.QObject):
             name = outname or filename.split('/')[-1].split('\\')[-1]
             name = outname or filename.split('/')[-1].split('\\')[-1]
 
 
             # New object creation and file processing
             # New object creation and file processing
-            ret = self.new_object("cncjob", name, obj_init, autoselected=False)
+            ret = self.new_object("cncjob", name, obj_init, autoselected=False, plot=plot)
             if ret == 'fail':
             if ret == 'fail':
                 self.inform.emit('[ERROR_NOTCL] %s' %
                 self.inform.emit('[ERROR_NOTCL] %s' %
                                  _("Failed to create CNCJob Object. Probable not a GCode file.\n "
                                  _("Failed to create CNCJob Object. Probable not a GCode file.\n "
@@ -9542,7 +9624,7 @@ class App(QtCore.QObject):
                              (_("Failed to open config file"), filename))
                              (_("Failed to open config file"), filename))
             return
             return
 
 
-    def open_project(self, filename, run_from_arg=None):
+    def open_project(self, filename, run_from_arg=None, plot=True, cli=None):
         """
         """
         Loads a project from the specified file.
         Loads a project from the specified file.
 
 
@@ -9551,16 +9633,21 @@ class App(QtCore.QObject):
         3) Calls on_file_new()
         3) Calls on_file_new()
         4) Updates options
         4) Updates options
         5) Calls new_object() with the object's from_dict() as init method.
         5) Calls new_object() with the object's from_dict() as init method.
-        6) Calls plot_all()
+        6) Calls plot_all() if plot=True
 
 
         :param filename:  Name of the file from which to load.
         :param filename:  Name of the file from which to load.
         :type filename: str
         :type filename: str
         :param run_from_arg: True if run for arguments
         :param run_from_arg: True if run for arguments
+        :param plot: If True plot all objects in the project
+        :param cli: run from command line
         :return: None
         :return: None
         """
         """
         App.log.debug("Opening project: " + filename)
         App.log.debug("Opening project: " + filename)
 
 
-        self.set_ui_title(name=_("Loading Project ... Please Wait ..."))
+        # for some reason, setting ui_title does not work when this method is called from Tcl Shell
+        # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
+        if cli is None:
+            self.set_ui_title(name=_("Loading Project ... Please Wait ..."))
 
 
         # Open and parse an uncompressed Project file
         # Open and parse an uncompressed Project file
         try:
         try:
@@ -9583,7 +9670,6 @@ class App(QtCore.QObject):
                 with lzma.open(filename) as f:
                 with lzma.open(filename) as f:
                     file_content = f.read().decode('utf-8')
                     file_content = f.read().decode('utf-8')
                     d = json.loads(file_content, object_hook=dict2obj)
                     d = json.loads(file_content, object_hook=dict2obj)
-
             except Exception as e:
             except Exception as e:
                 App.log.error("Failed to open project file: %s with error: %s" % (filename, str(e)))
                 App.log.error("Failed to open project file: %s with error: %s" % (filename, str(e)))
                 self.inform.emit('[ERROR_NOTCL] %s: %s' %
                 self.inform.emit('[ERROR_NOTCL] %s: %s' %
@@ -9594,13 +9680,19 @@ class App(QtCore.QObject):
         # # NOT THREAD SAFE # ##
         # # NOT THREAD SAFE # ##
         if run_from_arg is True:
         if run_from_arg is True:
             pass
             pass
+        elif cli is True:
+            self.delete_selection_shape()
         else:
         else:
             self.on_file_new()
             self.on_file_new()
 
 
         # Project options
         # Project options
         self.options.update(d['options'])
         self.options.update(d['options'])
         self.project_filename = filename
         self.project_filename = filename
-        self.set_screen_units(self.options["units"])
+
+        # for some reason, setting ui_title does not work when this method is called from Tcl Shell
+        # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
+        if cli is None:
+            self.set_screen_units(self.options["units"])
 
 
         # Re create objects
         # Re create objects
         App.log.debug(" **************** Started PROEJCT loading... **************** ")
         App.log.debug(" **************** Started PROEJCT loading... **************** ")
@@ -9608,24 +9700,31 @@ class App(QtCore.QObject):
         for obj in d['objs']:
         for obj in d['objs']:
             def obj_init(obj_inst, app_inst):
             def obj_init(obj_inst, app_inst):
                 obj_inst.from_dict(obj)
                 obj_inst.from_dict(obj)
+
             App.log.debug("Recreating from opened project an %s object: %s" %
             App.log.debug("Recreating from opened project an %s object: %s" %
                           (obj['kind'].capitalize(), obj['options']['name']))
                           (obj['kind'].capitalize(), obj['options']['name']))
 
 
-            self.set_ui_title(name="{} {}: {}".format(_("Loading Project ... restoring"),
-                                                      obj['kind'].upper(),
-                                                      obj['options']['name']
-                                                      )
-                              )
+            # for some reason, setting ui_title does not work when this method is called from Tcl Shell
+            # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
+            if cli is None:
+                self.set_ui_title(name="{} {}: {}".format(_("Loading Project ... restoring"),
+                                                          obj['kind'].upper(),
+                                                          obj['options']['name']
+                                                          )
+                                  )
 
 
-            self.new_object(obj['kind'], obj['options']['name'], obj_init, active=False, fit=False, plot=True)
+            self.new_object(obj['kind'], obj['options']['name'], obj_init, active=False, fit=False, plot=plot)
 
 
-        # self.plot_all()
         self.inform.emit('[success] %s: %s' %
         self.inform.emit('[success] %s: %s' %
                          (_("Project loaded from"), filename))
                          (_("Project loaded from"), filename))
 
 
         self.should_we_save = False
         self.should_we_save = False
         self.file_opened.emit("project", filename)
         self.file_opened.emit("project", filename)
-        self.set_ui_title(name=self.project_filename)
+
+        # for some reason, setting ui_title does not work when this method is called from Tcl Shell
+        # it's because the TclCommand is run in another thread (it inherit TclCommandSignaled)
+        if cli is None:
+            self.set_ui_title(name=self.project_filename)
 
 
         App.log.debug(" **************** Finished PROJECT loading... **************** ")
         App.log.debug(" **************** Finished PROJECT loading... **************** ")
 
 

+ 63 - 53
FlatCAMObj.py

@@ -600,7 +600,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
         # Show/Hide Advanced Options
         # Show/Hide Advanced Options
         if self.app.defaults["global_app_level"] == 'b':
         if self.app.defaults["global_app_level"] == 'b':
             self.ui.level.setText(_(
             self.ui.level.setText(_(
-                '<span style="color:green;"><b>Basic</b></span>'
+                '<span style="color:green;"><b>%s</b></span>' % _('Basic')
             ))
             ))
             self.ui.apertures_table_label.hide()
             self.ui.apertures_table_label.hide()
             self.ui.aperture_table_visibility_cb.hide()
             self.ui.aperture_table_visibility_cb.hide()
@@ -613,7 +613,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
             self.ui.except_cb.hide()
             self.ui.except_cb.hide()
         else:
         else:
             self.ui.level.setText(_(
             self.ui.level.setText(_(
-                '<span style="color:red;"><b>Advanced</b></span>'
+                '<span style="color:red;"><b>%s</b></span>' % _('Advanced')
             ))
             ))
 
 
         if self.app.defaults["gerber_buffering"] == 'no':
         if self.app.defaults["gerber_buffering"] == 'no':
@@ -923,8 +923,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
         except Exception as e:
         except Exception as e:
             return "Operation failed: %s" % str(e)
             return "Operation failed: %s" % str(e)
 
 
-    def isolate(self, iso_type=None, dia=None, passes=None, overlap=None,
-                outname=None, combine=None, milling_type=None, follow=None):
+    def isolate(self, iso_type=None, dia=None, passes=None, overlap=None, outname=None, combine=None,
+                milling_type=None, follow=None, plot=True):
         """
         """
         Creates an isolation routing geometry object in the project.
         Creates an isolation routing geometry object in the project.
 
 
@@ -947,13 +947,13 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
             combine = bool(combine)
             combine = bool(combine)
         if milling_type is None:
         if milling_type is None:
             milling_type = self.options["milling_type"]
             milling_type = self.options["milling_type"]
+
         if iso_type is None:
         if iso_type is None:
             self.iso_type = 2
             self.iso_type = 2
         else:
         else:
             self.iso_type = iso_type
             self.iso_type = iso_type
 
 
-        base_name = self.options["name"] + "_iso"
-        base_name = outname or base_name
+        base_name = self.options["name"]
 
 
         def generate_envelope(offset, invert, envelope_iso_type=2, follow=None, passes=0):
         def generate_envelope(offset, invert, envelope_iso_type=2, follow=None, passes=0):
             # isolation_geometry produces an envelope that is going on the left of the geometry
             # isolation_geometry produces an envelope that is going on the left of the geometry
@@ -1061,12 +1061,15 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
             return new_geometry
             return new_geometry
 
 
         if combine:
         if combine:
-            if self.iso_type == 0:
-                iso_name = self.options["name"] + "_ext_iso"
-            elif self.iso_type == 1:
-                iso_name = self.options["name"] + "_int_iso"
+            if outname is None:
+                if self.iso_type == 0:
+                    iso_name = base_name + "_ext_iso"
+                elif self.iso_type == 1:
+                    iso_name = base_name + "_int_iso"
+                else:
+                    iso_name = base_name + "_iso"
             else:
             else:
-                iso_name = base_name
+                iso_name = outname
 
 
             # TODO: This is ugly. Create way to pass data into init function.
             # TODO: This is ugly. Create way to pass data into init function.
             def iso_init(geo_obj, app_obj):
             def iso_init(geo_obj, app_obj):
@@ -1161,25 +1164,31 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
                     geo_obj.solid_geometry = area_subtraction(geo_obj.solid_geometry)
                     geo_obj.solid_geometry = area_subtraction(geo_obj.solid_geometry)
 
 
             # TODO: Do something if this is None. Offer changing name?
             # TODO: Do something if this is None. Offer changing name?
-            self.app.new_object("geometry", iso_name, iso_init)
+            self.app.new_object("geometry", iso_name, iso_init, plot=plot)
         else:
         else:
             for i in range(passes):
             for i in range(passes):
 
 
                 offset = dia * ((2 * i + 1) / 2.0) - (i * overlap * dia)
                 offset = dia * ((2 * i + 1) / 2.0) - (i * overlap * dia)
                 if passes > 1:
                 if passes > 1:
-                    if self.iso_type == 0:
-                        iso_name = self.options["name"] + "_ext_iso" + str(i + 1)
-                    elif self.iso_type == 1:
-                        iso_name = self.options["name"] + "_int_iso" + str(i + 1)
+                    if outname is None:
+                        if self.iso_type == 0:
+                            iso_name = base_name + "_ext_iso" + str(i + 1)
+                        elif self.iso_type == 1:
+                            iso_name = base_name + "_int_iso" + str(i + 1)
+                        else:
+                            iso_name = base_name + "_iso" + str(i + 1)
                     else:
                     else:
-                        iso_name = base_name + str(i + 1)
+                        iso_name = outname
                 else:
                 else:
-                    if self.iso_type == 0:
-                        iso_name = self.options["name"] + "_ext_iso"
-                    elif self.iso_type == 1:
-                        iso_name = self.options["name"] + "_int_iso"
+                    if outname is None:
+                        if self.iso_type == 0:
+                            iso_name = base_name + "_ext_iso"
+                        elif self.iso_type == 1:
+                            iso_name = base_name + "_int_iso"
+                        else:
+                            iso_name = base_name + "_iso"
                     else:
                     else:
-                        iso_name = base_name
+                        iso_name = outname
 
 
                 # TODO: This is ugly. Create way to pass data into init function.
                 # TODO: This is ugly. Create way to pass data into init function.
                 def iso_init(geo_obj, app_obj):
                 def iso_init(geo_obj, app_obj):
@@ -1230,7 +1239,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
                         geo_obj.solid_geometry = area_subtraction(geo_obj.solid_geometry)
                         geo_obj.solid_geometry = area_subtraction(geo_obj.solid_geometry)
 
 
                 # TODO: Do something if this is None. Offer changing name?
                 # TODO: Do something if this is None. Offer changing name?
-                self.app.new_object("geometry", iso_name, iso_init)
+                self.app.new_object("geometry", iso_name, iso_init, plot=plot)
 
 
     def on_plot_cb_click(self, *args):
     def on_plot_cb_click(self, *args):
         if self.muted_ui:
         if self.muted_ui:
@@ -2316,14 +2325,12 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
         # Show/Hide Advanced Options
         # Show/Hide Advanced Options
         if self.app.defaults["global_app_level"] == 'b':
         if self.app.defaults["global_app_level"] == 'b':
             self.ui.level.setText(_(
             self.ui.level.setText(_(
-                '<span style="color:green;"><b>Basic</b></span>'
+                '<span style="color:green;"><b>%s</b></span>' % _('Basic')
             ))
             ))
 
 
             self.ui.tools_table.setColumnHidden(4, True)
             self.ui.tools_table.setColumnHidden(4, True)
             self.ui.estartz_label.hide()
             self.ui.estartz_label.hide()
             self.ui.estartz_entry.hide()
             self.ui.estartz_entry.hide()
-            self.ui.eendz_label.hide()
-            self.ui.eendz_entry.hide()
             self.ui.feedrate_rapid_label.hide()
             self.ui.feedrate_rapid_label.hide()
             self.ui.feedrate_rapid_entry.hide()
             self.ui.feedrate_rapid_entry.hide()
             self.ui.pdepth_label.hide()
             self.ui.pdepth_label.hide()
@@ -2332,7 +2339,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             self.ui.feedrate_probe_entry.hide()
             self.ui.feedrate_probe_entry.hide()
         else:
         else:
             self.ui.level.setText(_(
             self.ui.level.setText(_(
-                '<span style="color:red;"><b>Advanced</b></span>'
+                '<span style="color:red;"><b>%s</b></span>' % _('Advanced')
             ))
             ))
 
 
         assert isinstance(self.ui, ExcellonObjectUI), \
         assert isinstance(self.ui, ExcellonObjectUI), \
@@ -2595,7 +2602,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
 
 
         return has_slots, excellon_code
         return has_slots, excellon_code
 
 
-    def generate_milling_drills(self, tools=None, outname=None, tooldia=None, use_thread=False):
+    def generate_milling_drills(self, tools=None, outname=None, tooldia=None, plot=False, use_thread=False):
         """
         """
         Note: This method is a good template for generic operations as
         Note: This method is a good template for generic operations as
         it takes it's options from parameters or otherwise from the
         it takes it's options from parameters or otherwise from the
@@ -2674,7 +2681,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
                             Point(hole['point']).buffer(buffer_value).exterior)
                             Point(hole['point']).buffer(buffer_value).exterior)
         if use_thread:
         if use_thread:
             def geo_thread(app_obj):
             def geo_thread(app_obj):
-                app_obj.new_object("geometry", outname, geo_init)
+                app_obj.new_object("geometry", outname, geo_init, plot=plot)
                 app_obj.progress.emit(100)
                 app_obj.progress.emit(100)
 
 
             # Create a promise with the new name
             # Create a promise with the new name
@@ -2683,11 +2690,11 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             # Send to worker
             # Send to worker
             self.app.worker_task.emit({'fcn': geo_thread, 'params': [self.app]})
             self.app.worker_task.emit({'fcn': geo_thread, 'params': [self.app]})
         else:
         else:
-            self.app.new_object("geometry", outname, geo_init)
+            self.app.new_object("geometry", outname, geo_init, plot=plot)
 
 
         return True, ""
         return True, ""
 
 
-    def generate_milling_slots(self, tools=None, outname=None, tooldia=None, use_thread=False):
+    def generate_milling_slots(self, tools=None, outname=None, tooldia=None, plot=True, use_thread=False):
         """
         """
         Note: This method is a good template for generic operations as
         Note: This method is a good template for generic operations as
         it takes it's options from parameters or otherwise from the
         it takes it's options from parameters or otherwise from the
@@ -2781,7 +2788,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
 
 
         if use_thread:
         if use_thread:
             def geo_thread(app_obj):
             def geo_thread(app_obj):
-                app_obj.new_object("geometry", outname + '_slot', geo_init)
+                app_obj.new_object("geometry", outname + '_slot', geo_init, plot=plot)
                 app_obj.progress.emit(100)
                 app_obj.progress.emit(100)
 
 
             # Create a promise with the new name
             # Create a promise with the new name
@@ -2790,7 +2797,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
             # Send to worker
             # Send to worker
             self.app.worker_task.emit({'fcn': geo_thread, 'params': [self.app]})
             self.app.worker_task.emit({'fcn': geo_thread, 'params': [self.app]})
         else:
         else:
-            self.app.new_object("geometry", outname + '_slot', geo_init)
+            self.app.new_object("geometry", outname + '_slot', geo_init, plot=plot)
 
 
         return True, ""
         return True, ""
 
 
@@ -3596,7 +3603,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
         # Show/Hide Advanced Options
         # Show/Hide Advanced Options
         if self.app.defaults["global_app_level"] == 'b':
         if self.app.defaults["global_app_level"] == 'b':
             self.ui.level.setText(_(
             self.ui.level.setText(_(
-                '<span style="color:green;"><b>Basic</b></span>'
+                '<span style="color:green;"><b>%s</b></span>' % _('Basic')
             ))
             ))
 
 
             self.ui.geo_tools_table.setColumnHidden(2, True)
             self.ui.geo_tools_table.setColumnHidden(2, True)
@@ -3607,8 +3614,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             self.ui.addtool_btn.hide()
             self.ui.addtool_btn.hide()
             self.ui.copytool_btn.hide()
             self.ui.copytool_btn.hide()
             self.ui.deltool_btn.hide()
             self.ui.deltool_btn.hide()
-            self.ui.endzlabel.hide()
-            self.ui.gendz_entry.hide()
+            # self.ui.endzlabel.hide()
+            # self.ui.gendz_entry.hide()
             self.ui.fr_rapidlabel.hide()
             self.ui.fr_rapidlabel.hide()
             self.ui.cncfeedrate_rapid_entry.hide()
             self.ui.cncfeedrate_rapid_entry.hide()
             self.ui.extracut_cb.hide()
             self.ui.extracut_cb.hide()
@@ -3618,7 +3625,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             self.ui.feedrate_probe_entry.hide()
             self.ui.feedrate_probe_entry.hide()
         else:
         else:
             self.ui.level.setText(_(
             self.ui.level.setText(_(
-                '<span style="color:red;"><b>Advanced</b></span>'
+                '<span style="color:red;"><b>%s</b></span>' % _('Advanced')
             ))
             ))
         self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click)
         self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click)
         self.ui.generate_cnc_button.clicked.connect(self.on_generatecnc_button_click)
         self.ui.generate_cnc_button.clicked.connect(self.on_generatecnc_button_click)
@@ -4518,7 +4525,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             self.app.inform.emit('[ERROR_NOTCL] %s' %
             self.app.inform.emit('[ERROR_NOTCL] %s' %
                                  _("Failed. No tool selected in the tool table ..."))
                                  _("Failed. No tool selected in the tool table ..."))
 
 
-    def mtool_gen_cncjob(self, outname=None, tools_dict=None, tools_in_use=None, segx=None, segy=None, use_thread=True):
+    def mtool_gen_cncjob(self, outname=None, tools_dict=None, tools_in_use=None, segx=None, segy=None,
+                         plot=True, use_thread=True):
         """
         """
         Creates a multi-tool CNCJob out of this Geometry object.
         Creates a multi-tool CNCJob out of this Geometry object.
         The actual work is done by the target FlatCAMCNCjob object's
         The actual work is done by the target FlatCAMCNCjob object's
@@ -4875,7 +4883,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             def job_thread(app_obj):
             def job_thread(app_obj):
                 if self.solid_geometry:
                 if self.solid_geometry:
                     with self.app.proc_container.new(_("Generating CNC Code")):
                     with self.app.proc_container.new(_("Generating CNC Code")):
-                        if app_obj.new_object("cncjob", outname, job_init_single_geometry) != 'fail':
+                        if app_obj.new_object("cncjob", outname, job_init_single_geometry, plot=plot) != 'fail':
                             app_obj.inform.emit('[success] %s: %s' %
                             app_obj.inform.emit('[success] %s: %s' %
                                                 (_("CNCjob created")), outname)
                                                 (_("CNCjob created")), outname)
                             app_obj.progress.emit(100)
                             app_obj.progress.emit(100)
@@ -4892,22 +4900,23 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
             self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
         else:
         else:
             if self.solid_geometry:
             if self.solid_geometry:
-                self.app.new_object("cncjob", outname, job_init_single_geometry)
+                self.app.new_object("cncjob", outname, job_init_single_geometry, plot=plot)
             else:
             else:
-                self.app.new_object("cncjob", outname, job_init_multi_geometry)
+                self.app.new_object("cncjob", outname, job_init_multi_geometry, plot=plot)
 
 
     def generatecncjob(
     def generatecncjob(
             self, outname=None,
             self, outname=None,
-            tooldia=None, offset=None,
+            dia=None, offset=None,
             z_cut=None, z_move=None,
             z_cut=None, z_move=None,
             feedrate=None, feedrate_z=None, feedrate_rapid=None,
             feedrate=None, feedrate_z=None, feedrate_rapid=None,
             spindlespeed=None, dwell=None, dwelltime=None,
             spindlespeed=None, dwell=None, dwelltime=None,
             multidepth=None, depthperpass=None,
             multidepth=None, depthperpass=None,
             toolchange=None, toolchangez=None, toolchangexy=None,
             toolchange=None, toolchangez=None, toolchangexy=None,
             extracut=None, startz=None, endz=None,
             extracut=None, startz=None, endz=None,
-            ppname_g=None,
+            pp=None,
             segx=None, segy=None,
             segx=None, segy=None,
-            use_thread=True):
+            use_thread=True,
+            plot=True):
         """
         """
         Only used for TCL Command.
         Only used for TCL Command.
         Creates a CNCJob out of this Geometry object. The actual
         Creates a CNCJob out of this Geometry object. The actual
@@ -4919,14 +4928,14 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
         :param feedrate: Feed rate while cutting on X - Y plane
         :param feedrate: Feed rate while cutting on X - Y plane
         :param feedrate_z: Feed rate while cutting on Z plane
         :param feedrate_z: Feed rate while cutting on Z plane
         :param feedrate_rapid: Feed rate while moving with rapids
         :param feedrate_rapid: Feed rate while moving with rapids
-        :param tooldia: Tool diameter
+        :param dia: Tool diameter
         :param outname: Name of the new object
         :param outname: Name of the new object
         :param spindlespeed: Spindle speed (RPM)
         :param spindlespeed: Spindle speed (RPM)
-        :param ppname_g Name of the postprocessor
+        :param pp Name of the postprocessor
         :return: None
         :return: None
         """
         """
 
 
-        tooldia = tooldia if tooldia else float(self.options["cnctooldia"])
+        tooldia = dia if dia else float(self.options["cnctooldia"])
         outname = outname if outname is not None else self.options["name"]
         outname = outname if outname is not None else self.options["name"]
 
 
         z_cut = z_cut if z_cut is not None else float(self.options["cutz"])
         z_cut = z_cut if z_cut is not None else float(self.options["cutz"])
@@ -4957,7 +4966,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
         dwell = dwell if dwell else self.options["dwell"]
         dwell = dwell if dwell else self.options["dwell"]
         dwelltime = dwelltime if dwelltime else float(self.options["dwelltime"])
         dwelltime = dwelltime if dwelltime else float(self.options["dwelltime"])
 
 
-        ppname_g = ppname_g if ppname_g else self.options["ppname_g"]
+        ppname_g = pp if pp else self.options["ppname_g"]
 
 
         # Object initialization function for app.new_object()
         # Object initialization function for app.new_object()
         # RUNNING ON SEPARATE THREAD!
         # RUNNING ON SEPARATE THREAD!
@@ -5034,7 +5043,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             # To be run in separate thread
             # To be run in separate thread
             def job_thread(app_obj):
             def job_thread(app_obj):
                 with self.app.proc_container.new(_("Generating CNC Code")):
                 with self.app.proc_container.new(_("Generating CNC Code")):
-                    app_obj.new_object("cncjob", outname, job_init)
+                    app_obj.new_object("cncjob", outname, job_init, plot=plot)
                     app_obj.inform.emit('[success] %s: %s' %
                     app_obj.inform.emit('[success] %s: %s' %
                                         (_("CNCjob created")), outname)
                                         (_("CNCjob created")), outname)
                     app_obj.progress.emit(100)
                     app_obj.progress.emit(100)
@@ -5044,7 +5053,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
             # Send to worker
             # Send to worker
             self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
             self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
         else:
         else:
-            self.app.new_object("cncjob", outname, job_init)
+            self.app.new_object("cncjob", outname, job_init, plot=plot)
 
 
     # def on_plot_cb_click(self, *args):  # TODO: args not needed
     # def on_plot_cb_click(self, *args):  # TODO: args not needed
     #     if self.muted_ui:
     #     if self.muted_ui:
@@ -5833,11 +5842,12 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
 
 
         preamble = str(self.ui.prepend_text.get_value())
         preamble = str(self.ui.prepend_text.get_value())
         postamble = str(self.ui.append_text.get_value())
         postamble = str(self.ui.append_text.get_value())
-        gc = self.export_gcode(preamble=preamble, postamble=postamble, to_file=True)
-        if gc == 'fail':
+
+        gco = self.export_gcode(preamble=preamble, postamble=postamble, to_file=True)
+        if gco == 'fail':
             return
             return
         else:
         else:
-            self.app.gcode_edited = gc
+            self.app.gcode_edited = gco
 
 
         self.app.init_code_editor(name=_("Code Editor"))
         self.app.init_code_editor(name=_("Code Editor"))
         self.app.ui.buttonOpen.clicked.connect(self.app.handleOpen)
         self.app.ui.buttonOpen.clicked.connect(self.app.handleOpen)

+ 1 - 1
ObjectCollection.py

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

+ 24 - 0
README.md

@@ -9,6 +9,18 @@ CAD program, and create G-Code for Isolation routing.
 
 
 =================================================
 =================================================
 
 
+16.09.2019
+
+- modified the TclCommand New so it will no longer close all tabs when called (it closed the Code Editor tab which may have been holding the code that run)
+- fixed the App.on_view_source() method for CNCJob objects: the Gcode will now contain the Prepend and Append code from the Edit -> Preferences -> CNCJob -> CNCJob Options
+- added a new parameter named 'muted' for the TclCommands: cncjob, drillcncjob and write_gcode. Setting it as -muted 1 will disable the error reporting in TCL Shell
+- some GUI optimizations
+- more GUI optimizations related to being part of the Advanced category or not
+- added possibility to change the positive SVG exported file color in Tool Film
+- fixed some issues recently introduced in the TclCommands CNCJob, DrillCNCJob and write_gcode; changed some parameters names
+- fixed issue in the Laser postprocessor where the laser was turned on as soon as the GCode started creating an unwanted cut up until the job start
+- added new links in Menu -> Help (Excellon, Gerber specifications and a Report Bug)
+
 15.09.2019
 15.09.2019
 
 
 - refactored FlatCAMGeometry.mtool_gen_cncjob() method
 - refactored FlatCAMGeometry.mtool_gen_cncjob() method
@@ -19,6 +31,18 @@ CAD program, and create G-Code for Isolation routing.
 - finished updating the TclCommand cncjob to work for multi-geo Geometry objects with the parameters from the args
 - finished updating the TclCommand cncjob to work for multi-geo Geometry objects with the parameters from the args
 - fixed the TclCommand cncjob to use the -outname parameter
 - fixed the TclCommand cncjob to use the -outname parameter
 - added some more keywords in the data_model for auto-completer
 - added some more keywords in the data_model for auto-completer
+- fixed isolate TclCommand to use correctly the -outname parameter
+- added possibility to see the GCode when right clicking on the Project tab on a CNCJob object and then clicking View Source
+- added a new TclCommand named PlotObjects which will plot a list of FlatCAM objects
+- made that after opening an object in FlatCAM it is not automatically plotted. If the user wants to plot it can use the TclCommands PlotAll or PlotObjects
+- modified the TclCommands so that open files do not plot the opened files automatically
+- made all TclCommands not to be plotted automatically
+- made sure that all TclCommands are not threaded
+- added new TclCommands: NewExcellon, NewGerber
+- fixed the TclCommand open_project
+- added the outname parameter (and established an default name when outname not used) for the AlignDrillGrid and AlignDrill TclCommands
+- fixed Scripts repeating multiple time when the Code Editor is used. This repetition was correlated with multiple openings of the Code Editor window (especially after an error)
+- added the autocomplete keywords that can be changed to the defaults dictionary
 
 
 14.09.2019
 14.09.2019
 
 

+ 34 - 20
camlib.py

@@ -5685,10 +5685,11 @@ class CNCjob(Geometry):
             must_visit.remove(nearest)
             must_visit.remove(nearest)
         return path
         return path
 
 
-    def generate_from_excellon_by_tool(self, exobj, tools="all", drillz = 3.0,
-                                       toolchange=False, toolchangez=0.1, toolchangexy='',
-                                       endz=2.0, startz=None,
-                                       excellon_optimization_type='B'):
+    def generate_from_excellon_by_tool(
+            self, exobj, tools="all", drillz = 3.0,
+            toolchange=False, toolchangez=0.1, toolchangexy='',
+            endz=2.0, startz=None,
+            excellon_optimization_type='B'):
         """
         """
         Creates gcode for this object from an Excellon object
         Creates gcode for this object from an Excellon object
         for the specified tools.
         for the specified tools.
@@ -6482,11 +6483,18 @@ class CNCjob(Geometry):
             #     self.gcode += self.doformat(p.toolchange_code)
             #     self.gcode += self.doformat(p.toolchange_code)
             self.gcode += self.doformat(p.toolchange_code)
             self.gcode += self.doformat(p.toolchange_code)
 
 
-            self.gcode += self.doformat(p.spindle_code)     # Spindle start
+            if 'laser' not in self.pp_geometry_name:
+                self.gcode += self.doformat(p.spindle_code)     # Spindle start
+            else:
+                # for laser this will disable the laser
+                self.gcode += self.doformat(p.lift_code, x=self.oldx, y=self.oldy)  # Move (up) to travel height
+
             if self.dwell is True:
             if self.dwell is True:
                 self.gcode += self.doformat(p.dwell_code)   # Dwell time
                 self.gcode += self.doformat(p.dwell_code)   # Dwell time
         else:
         else:
-            self.gcode += self.doformat(p.spindle_code)     # Spindle start
+            if 'laser' not in self.pp_geometry_name:
+                self.gcode += self.doformat(p.spindle_code)  # Spindle start
+
             if self.dwell is True:
             if self.dwell is True:
                 self.gcode += self.doformat(p.dwell_code)   # Dwell time
                 self.gcode += self.doformat(p.dwell_code)   # Dwell time
 
 
@@ -6589,15 +6597,16 @@ class CNCjob(Geometry):
                              )
                              )
         return self.gcode
         return self.gcode
 
 
-    def generate_from_geometry_2(self, geometry, append=True,
-                                 tooldia=None, offset=0.0, tolerance=0,
-                                 z_cut=1.0, z_move=2.0,
-                                 feedrate=2.0, feedrate_z=2.0, feedrate_rapid=30,
-                                 spindlespeed=None, spindledir='CW', dwell=False, dwelltime=1.0,
-                                 multidepth=False, depthpercut=None,
-                                 toolchange=False, toolchangez=1.0, toolchangexy="0.0, 0.0",
-                                 extracut=False, startz=None, endz=2.0,
-                                 pp_geometry_name=None, tool_no=1):
+    def generate_from_geometry_2(
+            self, geometry, append=True,
+            tooldia=None, offset=0.0, tolerance=0,
+            z_cut=1.0, z_move=2.0,
+            feedrate=2.0, feedrate_z=2.0, feedrate_rapid=30,
+            spindlespeed=None, spindledir='CW', dwell=False, dwelltime=1.0,
+            multidepth=False, depthpercut=None,
+            toolchange=False, toolchangez=1.0, toolchangexy="0.0, 0.0",
+            extracut=False, startz=None, endz=2.0,
+            pp_geometry_name=None, tool_no=1):
         """
         """
         Second algorithm to generate from Geometry.
         Second algorithm to generate from Geometry.
 
 
@@ -6825,13 +6834,18 @@ class CNCjob(Geometry):
             #     self.gcode += self.doformat(p.toolchange_code)
             #     self.gcode += self.doformat(p.toolchange_code)
             self.gcode += self.doformat(p.toolchange_code)
             self.gcode += self.doformat(p.toolchange_code)
 
 
-            self.gcode += self.doformat(p.spindle_code)     # Spindle start
+            if 'laser' not in self.pp_geometry_name:
+                self.gcode += self.doformat(p.spindle_code)     # Spindle start
+            else:
+                # for laser this will disable the laser
+                self.gcode += self.doformat(p.lift_code, x=self.oldx, y=self.oldy)  # Move (up) to travel height
 
 
             if self.dwell is True:
             if self.dwell is True:
                 self.gcode += self.doformat(p.dwell_code)   # Dwell time
                 self.gcode += self.doformat(p.dwell_code)   # Dwell time
-
         else:
         else:
-            self.gcode += self.doformat(p.spindle_code)     # Spindle start
+            if 'laser' not in self.pp_geometry_name:
+                self.gcode += self.doformat(p.spindle_code)  # Spindle start
+
             if self.dwell is True:
             if self.dwell is True:
                 self.gcode += self.doformat(p.dwell_code)   # Dwell time
                 self.gcode += self.doformat(p.dwell_code)   # Dwell time
 
 
@@ -7247,7 +7261,7 @@ class CNCjob(Geometry):
 
 
             match_lsr_pos = re.search(r"^(M0[3|5])", gline)
             match_lsr_pos = re.search(r"^(M0[3|5])", gline)
             if match_lsr_pos:
             if match_lsr_pos:
-                if match_lsr_pos.group(1) == 'M05':
+                if 'M05' in match_lsr_pos.group(1):
                     # the value does not matter, only that it is positive so the gcode_parse() know it is > 0,
                     # the value does not matter, only that it is positive so the gcode_parse() know it is > 0,
                     # therefore the move is of kind T (travel)
                     # therefore the move is of kind T (travel)
                     command['Z'] = 1
                     command['Z'] = 1
@@ -7316,7 +7330,7 @@ class CNCjob(Geometry):
                     pass
                     pass
                 elif 'hpgl' in self.pp_excellon_name or 'hpgl' in self.pp_geometry_name:
                 elif 'hpgl' in self.pp_excellon_name or 'hpgl' in self.pp_geometry_name:
                     pass
                     pass
-                elif 'grbl_laser' in self.pp_excellon_name or 'grbl_laser' in self.pp_geometry_name:
+                elif 'laser' in self.pp_excellon_name or 'laser' in self.pp_geometry_name:
                     pass
                     pass
                 elif ('X' in gobj or 'Y' in gobj) and gobj['Z'] != current['Z']:
                 elif ('X' in gobj or 'Y' in gobj) and gobj['Z'] != current['Z']:
                     if self.pp_geometry_name == 'line_xyz' or self.pp_excellon_name == 'line_xyz':
                     if self.pp_geometry_name == 'line_xyz' or self.pp_excellon_name == 'line_xyz':

+ 302 - 237
flatcamGUI/FlatCAMGUI.py

@@ -400,6 +400,15 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
         self.menuhelp_manual = self.menuhelp.addAction(QtGui.QIcon('share/globe16.png'), _('Online Help\tF1'))
         self.menuhelp_manual = self.menuhelp.addAction(QtGui.QIcon('share/globe16.png'), _('Online Help\tF1'))
         self.menuhelp_home = self.menuhelp.addAction(QtGui.QIcon('share/home16.png'), _('FlatCAM.org'))
         self.menuhelp_home = self.menuhelp.addAction(QtGui.QIcon('share/home16.png'), _('FlatCAM.org'))
         self.menuhelp.addSeparator()
         self.menuhelp.addSeparator()
+        self.menuhelp_report_bug = self.menuhelp.addAction(QtGui.QIcon('share/bug16.png'), _('Report a bug'))
+        self.menuhelp.addSeparator()
+        self.menuhelp_exc_spec = self.menuhelp.addAction(QtGui.QIcon('share/pdf_link16.png'),
+                                                         _('Excellon Specification'))
+        self.menuhelp_gerber_spec = self.menuhelp.addAction(QtGui.QIcon('share/pdf_link16.png'),
+                                                            _('Gerber Specification'))
+
+        self.menuhelp.addSeparator()
+
         self.menuhelp_shortcut_list = self.menuhelp.addAction(QtGui.QIcon('share/shortcuts24.png'),
         self.menuhelp_shortcut_list = self.menuhelp.addAction(QtGui.QIcon('share/shortcuts24.png'),
                                                               _('Shortcuts List\tF3'))
                                                               _('Shortcuts List\tF3'))
         self.menuhelp_videohelp = self.menuhelp.addAction(QtGui.QIcon('share/youtube32.png'), _('YouTube Channel\tF4')
         self.menuhelp_videohelp = self.menuhelp.addAction(QtGui.QIcon('share/youtube32.png'), _('YouTube Channel\tF4')
@@ -2044,7 +2053,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
 
 
     def eventFilter(self, obj, event):
     def eventFilter(self, obj, event):
         # filter the ToolTips display based on a Preferences setting
         # filter the ToolTips display based on a Preferences setting
-        if self.general_defaults_form.general_app_group.toggle_tooltips_cb.get_value() is False:
+        if self.general_defaults_form.general_gui_set_group.toggle_tooltips_cb.get_value() is False:
             if event.type() == QtCore.QEvent.ToolTip:
             if event.type() == QtCore.QEvent.ToolTip:
                 return True
                 return True
             else:
             else:
@@ -4026,6 +4035,7 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         )
         )
         self.selection_cb = FCCheckBox()
         self.selection_cb = FCCheckBox()
 
 
+        # Notebook Font Size
         self.notebook_font_size_label = QtWidgets.QLabel('%s:' % _('NB Font Size'))
         self.notebook_font_size_label = QtWidgets.QLabel('%s:' % _('NB Font Size'))
         self.notebook_font_size_label.setToolTip(
         self.notebook_font_size_label.setToolTip(
             _("This sets the font size for the elements found in the Notebook.\n"
             _("This sets the font size for the elements found in the Notebook.\n"
@@ -4074,6 +4084,56 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         else:
         else:
             self.splash_cb.set_value(False)
             self.splash_cb.set_value(False)
 
 
+        # Shell StartUp CB
+        self.shell_startup_label = QtWidgets.QLabel('%s:' % _('Shell at StartUp'))
+        self.shell_startup_label.setToolTip(
+            _("Check this box if you want the shell to\n"
+              "start automatically at startup.")
+        )
+        self.shell_startup_cb = FCCheckBox(label='')
+        self.shell_startup_cb.setToolTip(
+            _("Check this box if you want the shell to\n"
+              "start automatically at startup.")
+        )
+
+        # Project at StartUp CB
+        self.project_startup_label = QtWidgets.QLabel('%s:' % _('Project at StartUp'))
+        self.project_startup_label.setToolTip(
+            _("Check this box if you want the project/selected/tool tab area to\n"
+              "to be shown automatically at startup.")
+        )
+        self.project_startup_cb = FCCheckBox(label='')
+        self.project_startup_cb.setToolTip(
+            _("Check this box if you want the project/selected/tool tab area to\n"
+              "to be shown automatically at startup.")
+        )
+
+        # Project autohide CB
+        self.project_autohide_label = QtWidgets.QLabel('%s:' % _('Project AutoHide'))
+        self.project_autohide_label.setToolTip(
+            _("Check this box if you want the project/selected/tool tab area to\n"
+              "hide automatically when there are no objects loaded and\n"
+              "to show whenever a new object is created.")
+        )
+        self.project_autohide_cb = FCCheckBox(label='')
+        self.project_autohide_cb.setToolTip(
+            _("Check this box if you want the project/selected/tool tab area to\n"
+              "hide automatically when there are no objects loaded and\n"
+              "to show whenever a new object is created.")
+        )
+
+        # Enable/Disable ToolTips globally
+        self.toggle_tooltips_label = QtWidgets.QLabel('<b>%s:</b>' % _('Enable ToolTips'))
+        self.toggle_tooltips_label.setToolTip(
+            _("Check this box if you want to have toolTips displayed\n"
+              "when hovering with mouse over items throughout the App.")
+        )
+        self.toggle_tooltips_cb = FCCheckBox(label='')
+        self.toggle_tooltips_cb.setToolTip(
+            _("Check this box if you want to have toolTips displayed\n"
+              "when hovering with mouse over items throughout the App.")
+        )
+
         # Add (label - input field) pair to the QFormLayout
         # Add (label - input field) pair to the QFormLayout
         self.form_box.addRow(self.spacelabel, self.spacelabel)
         self.form_box.addRow(self.spacelabel, self.spacelabel)
 
 
@@ -4088,11 +4148,27 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
         self.form_box.addRow(self.axis_font_size_label, self.axis_font_size_spinner)
         self.form_box.addRow(self.axis_font_size_label, self.axis_font_size_spinner)
         self.form_box.addRow(QtWidgets.QLabel(''))
         self.form_box.addRow(QtWidgets.QLabel(''))
         self.form_box.addRow(self.splash_label, self.splash_cb)
         self.form_box.addRow(self.splash_label, self.splash_cb)
+        self.form_box.addRow(self.shell_startup_label, self.shell_startup_cb)
+        self.form_box.addRow(self.project_startup_label, self.project_startup_cb)
+        self.form_box.addRow(self.project_autohide_label, self.project_autohide_cb)
+        self.form_box.addRow(QtWidgets.QLabel(''))
+        self.form_box.addRow(self.toggle_tooltips_label, self.toggle_tooltips_cb)
 
 
         # Add the QFormLayout that holds the Application general defaults
         # Add the QFormLayout that holds the Application general defaults
         # to the main layout of this TAB
         # to the main layout of this TAB
         self.layout.addLayout(self.form_box)
         self.layout.addLayout(self.form_box)
 
 
+        # Delete confirmation
+        self.delete_conf_cb = FCCheckBox(_('Delete object confirmation'))
+        self.delete_conf_cb.setToolTip(
+            _("When checked the application will ask for user confirmation\n"
+              "whenever the Delete object(s) event is triggered, either by\n"
+              "menu shortcut or key shortcut.")
+        )
+        self.layout.addWidget(self.delete_conf_cb)
+
+        self.layout.addStretch()
+
     def handle_style(self, style):
     def handle_style(self, style):
         # set current style
         # set current style
         settings = QSettings("Open Source", "FlatCAM")
         settings = QSettings("Open Source", "FlatCAM")
@@ -4141,7 +4217,7 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
         self.form_box = QtWidgets.QFormLayout()
         self.form_box = QtWidgets.QFormLayout()
 
 
         # Units for FlatCAM
         # Units for FlatCAM
-        self.unitslabel = QtWidgets.QLabel('<b>%s:</b>' % _('Units'))
+        self.unitslabel = QtWidgets.QLabel('<span style="color:red;"><b>%s:</b></span>' % _('Units'))
         self.unitslabel.setToolTip(_("The default value for FlatCAM units.\n"
         self.unitslabel.setToolTip(_("The default value for FlatCAM units.\n"
                                      "Whatever is selected here is set every time\n"
                                      "Whatever is selected here is set every time\n"
                                      "FLatCAM is started."))
                                      "FLatCAM is started."))
@@ -4180,18 +4256,6 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
                                              "security features. In this case the language will be\n"
                                              "security features. In this case the language will be\n"
                                              "applied at the next app start."))
                                              "applied at the next app start."))
 
 
-        # Shell StartUp CB
-        self.shell_startup_label = QtWidgets.QLabel('%s:' % _('Shell at StartUp'))
-        self.shell_startup_label.setToolTip(
-            _("Check this box if you want the shell to\n"
-              "start automatically at startup.")
-        )
-        self.shell_startup_cb = FCCheckBox(label='')
-        self.shell_startup_cb.setToolTip(
-            _("Check this box if you want the shell to\n"
-              "start automatically at startup.")
-        )
-
         # Version Check CB
         # Version Check CB
         self.version_check_label = QtWidgets.QLabel('%s:' % _('Version Check'))
         self.version_check_label = QtWidgets.QLabel('%s:' % _('Version Check'))
         self.version_check_label.setToolTip(
         self.version_check_label.setToolTip(
@@ -4232,43 +4296,7 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
         self.mselect_radio = RadioSet([{'label': _('CTRL'), 'value': 'Control'},
         self.mselect_radio = RadioSet([{'label': _('CTRL'), 'value': 'Control'},
                                        {'label': _('SHIFT'), 'value': 'Shift'}])
                                        {'label': _('SHIFT'), 'value': 'Shift'}])
 
 
-        # Project at StartUp CB
-        self.project_startup_label = QtWidgets.QLabel('%s:' % _('Project at StartUp'))
-        self.project_startup_label.setToolTip(
-            _("Check this box if you want the project/selected/tool tab area to\n"
-              "to be shown automatically at startup.")
-        )
-        self.project_startup_cb = FCCheckBox(label='')
-        self.project_startup_cb.setToolTip(
-            _("Check this box if you want the project/selected/tool tab area to\n"
-              "to be shown automatically at startup.")
-        )
-
-        # Project autohide CB
-        self.project_autohide_label = QtWidgets.QLabel('%s:' % _('Project AutoHide'))
-        self.project_autohide_label.setToolTip(
-           _("Check this box if you want the project/selected/tool tab area to\n"
-             "hide automatically when there are no objects loaded and\n"
-             "to show whenever a new object is created.")
-        )
-        self.project_autohide_cb = FCCheckBox(label='')
-        self.project_autohide_cb.setToolTip(
-            _("Check this box if you want the project/selected/tool tab area to\n"
-              "hide automatically when there are no objects loaded and\n"
-              "to show whenever a new object is created.")
-        )
-
-        # Enable/Disable ToolTips globally
-        self.toggle_tooltips_label = QtWidgets.QLabel('<b>%s:</b>' % _('Enable ToolTips'))
-        self.toggle_tooltips_label.setToolTip(
-           _("Check this box if you want to have toolTips displayed\n"
-             "when hovering with mouse over items throughout the App.")
-        )
-        self.toggle_tooltips_cb = FCCheckBox(label='')
-        self.toggle_tooltips_cb.setToolTip(
-           _("Check this box if you want to have toolTips displayed\n"
-             "when hovering with mouse over items throughout the App.")
-        )
+       # Worker Numbers
         self.worker_number_label = QtWidgets.QLabel('%s:' % _('Workers number'))
         self.worker_number_label = QtWidgets.QLabel('%s:' % _('Workers number'))
         self.worker_number_label.setToolTip(
         self.worker_number_label.setToolTip(
             _("The number of Qthreads made available to the App.\n"
             _("The number of Qthreads made available to the App.\n"
@@ -4321,15 +4349,11 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
         self.form_box.addRow(self.languagespace, self.language_apply_btn)
         self.form_box.addRow(self.languagespace, self.language_apply_btn)
 
 
         self.form_box.addRow(self.spacelabel, self.spacelabel)
         self.form_box.addRow(self.spacelabel, self.spacelabel)
-        self.form_box.addRow(self.shell_startup_label, self.shell_startup_cb)
         self.form_box.addRow(self.version_check_label, self.version_check_cb)
         self.form_box.addRow(self.version_check_label, self.version_check_cb)
         self.form_box.addRow(self.send_stats_label, self.send_stats_cb)
         self.form_box.addRow(self.send_stats_label, self.send_stats_cb)
 
 
         self.form_box.addRow(self.panbuttonlabel, self.pan_button_radio)
         self.form_box.addRow(self.panbuttonlabel, self.pan_button_radio)
         self.form_box.addRow(self.mselectlabel, self.mselect_radio)
         self.form_box.addRow(self.mselectlabel, self.mselect_radio)
-        self.form_box.addRow(self.project_startup_label, self.project_startup_cb)
-        self.form_box.addRow(self.project_autohide_label, self.project_autohide_cb)
-        self.form_box.addRow(self.toggle_tooltips_label, self.toggle_tooltips_cb)
         self.form_box.addRow(self.worker_number_label, self.worker_number_sb)
         self.form_box.addRow(self.worker_number_label, self.worker_number_sb)
         self.form_box.addRow(tol_label, self.tol_entry)
         self.form_box.addRow(tol_label, self.tol_entry)
 
 
@@ -4350,15 +4374,6 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
         # self.advanced_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
         # self.advanced_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
         self.layout.addWidget(self.open_style_cb)
         self.layout.addWidget(self.open_style_cb)
 
 
-        # Delete confirmation
-        self.delete_conf_cb = FCCheckBox(_('Delete object confirmation'))
-        self.delete_conf_cb.setToolTip(
-            _("When checked the application will ask for user confirmation\n"
-              "whenever the Delete object(s) event is triggered, either by\n"
-              "menu shortcut or key shortcut.")
-        )
-        self.layout.addWidget(self.delete_conf_cb)
-
         # Save compressed project CB
         # Save compressed project CB
         self.save_type_cb = FCCheckBox(_('Save Compressed Project'))
         self.save_type_cb = FCCheckBox(_('Save Compressed Project'))
         self.save_type_cb.setToolTip(
         self.save_type_cb.setToolTip(
@@ -4442,40 +4457,6 @@ class GerberGenPrefGroupUI(OptionsGroupUI):
         grid0.addWidget(self.circle_steps_label, 1, 0)
         grid0.addWidget(self.circle_steps_label, 1, 0)
         grid0.addWidget(self.circle_steps_entry, 1, 1)
         grid0.addWidget(self.circle_steps_entry, 1, 1)
 
 
-        # Milling Type
-        buffering_label = QtWidgets.QLabel('%s:' % _('Buffering'))
-        buffering_label.setToolTip(
-            _("Buffering type:\n"
-              "- None --> best performance, fast file loading but no so good display\n"
-              "- Full --> slow file loading but good visuals. This is the default.\n"
-              "<<WARNING>>: Don't change this unless you know what you are doing !!!")
-        )
-        self.buffering_radio = RadioSet([{'label': _('None'), 'value': 'no'},
-                                          {'label': _('Full'), 'value': 'full'}])
-        grid0.addWidget(buffering_label, 2, 0)
-        grid0.addWidget(self.buffering_radio, 2, 1)
-
-        # Simplification
-        self.simplify_cb = FCCheckBox(label=_('Simplify'))
-        self.simplify_cb.setToolTip(_("When checked all the Gerber polygons will be\n"
-                                      "loaded with simplification having a set tolerance."))
-        grid0.addWidget(self.simplify_cb, 3, 0)
-
-        # Simplification tolerance
-        self.simplification_tol_label = QtWidgets.QLabel(_('Tolerance'))
-        self.simplification_tol_label.setToolTip(_("Tolerance for poligon simplification."))
-
-        self.simplification_tol_spinner = FCDoubleSpinner()
-        self.simplification_tol_spinner.set_precision(5)
-        self.simplification_tol_spinner.setWrapping(True)
-        self.simplification_tol_spinner.setRange(0.00000, 0.01000)
-        self.simplification_tol_spinner.setSingleStep(0.0001)
-
-        grid0.addWidget(self.simplification_tol_label, 4, 0)
-        grid0.addWidget(self.simplification_tol_spinner, 4, 1)
-        self.ois_simplif = OptionalInputSection(self.simplify_cb,
-                                                [self.simplification_tol_label, self.simplification_tol_spinner],
-                                                logic=True)
         self.layout.addStretch()
         self.layout.addStretch()
 
 
 
 
@@ -4525,7 +4506,11 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
               "A value here of 0.25 means an overlap of 25%% from the tool diameter found above.")
               "A value here of 0.25 means an overlap of 25%% from the tool diameter found above.")
         )
         )
         grid0.addWidget(overlabel, 2, 0)
         grid0.addWidget(overlabel, 2, 0)
-        self.iso_overlap_entry = FloatEntry()
+        self.iso_overlap_entry = FCDoubleSpinner()
+        self.iso_overlap_entry.set_precision(3)
+        self.iso_overlap_entry.setWrapping(True)
+        self.iso_overlap_entry.setRange(0.000, 0.999)
+        self.iso_overlap_entry.setSingleStep(0.1)
         grid0.addWidget(self.iso_overlap_entry, 2, 1)
         grid0.addWidget(self.iso_overlap_entry, 2, 1)
 
 
         # Milling Type
         # Milling Type
@@ -4615,7 +4600,7 @@ class GerberAdvOptPrefGroupUI(OptionsGroupUI):
         self.setTitle(str(_("Gerber Adv. Options")))
         self.setTitle(str(_("Gerber Adv. Options")))
 
 
         # ## Advanced Gerber Parameters
         # ## Advanced Gerber Parameters
-        self.adv_param_label = QtWidgets.QLabel("<b>%s:</b>" % _("Advanced Param."))
+        self.adv_param_label = QtWidgets.QLabel('<b>%s:</b>' % _('Advanced Options'))
         self.adv_param_label.setToolTip(
         self.adv_param_label.setToolTip(
             _("A list of Gerber advanced parameters.\n"
             _("A list of Gerber advanced parameters.\n"
               "Those parameters are available only for\n"
               "Those parameters are available only for\n"
@@ -4633,7 +4618,7 @@ class GerberAdvOptPrefGroupUI(OptionsGroupUI):
               "This means that it will cut through\n"
               "This means that it will cut through\n"
               "the middle of the trace.")
               "the middle of the trace.")
         )
         )
-        grid0.addWidget(self.follow_cb, 0, 0)
+        grid0.addWidget(self.follow_cb, 0, 0, 1, 2)
 
 
         # Aperture Table Visibility CB
         # Aperture Table Visibility CB
         self.aperture_table_visibility_cb = FCCheckBox(label=_('Table Show/Hide'))
         self.aperture_table_visibility_cb = FCCheckBox(label=_('Table Show/Hide'))
@@ -4643,7 +4628,42 @@ class GerberAdvOptPrefGroupUI(OptionsGroupUI):
               "that are drawn on canvas.")
               "that are drawn on canvas.")
 
 
         )
         )
-        grid0.addWidget(self.aperture_table_visibility_cb, 1, 0)
+        grid0.addWidget(self.aperture_table_visibility_cb, 1, 0, 1, 2)
+
+        # Buffering Type
+        buffering_label = QtWidgets.QLabel('%s:' % _('Buffering'))
+        buffering_label.setToolTip(
+            _("Buffering type:\n"
+              "- None --> best performance, fast file loading but no so good display\n"
+              "- Full --> slow file loading but good visuals. This is the default.\n"
+              "<<WARNING>>: Don't change this unless you know what you are doing !!!")
+        )
+        self.buffering_radio = RadioSet([{'label': _('None'), 'value': 'no'},
+                                          {'label': _('Full'), 'value': 'full'}])
+        grid0.addWidget(buffering_label, 2, 0)
+        grid0.addWidget(self.buffering_radio, 2, 1)
+
+        # Simplification
+        self.simplify_cb = FCCheckBox(label=_('Simplify'))
+        self.simplify_cb.setToolTip(_("When checked all the Gerber polygons will be\n"
+                                      "loaded with simplification having a set tolerance."))
+        grid0.addWidget(self.simplify_cb, 3, 0, 1, 2)
+
+        # Simplification tolerance
+        self.simplification_tol_label = QtWidgets.QLabel(_('Tolerance'))
+        self.simplification_tol_label.setToolTip(_("Tolerance for poligon simplification."))
+
+        self.simplification_tol_spinner = FCDoubleSpinner()
+        self.simplification_tol_spinner.set_precision(5)
+        self.simplification_tol_spinner.setWrapping(True)
+        self.simplification_tol_spinner.setRange(0.00000, 0.01000)
+        self.simplification_tol_spinner.setSingleStep(0.0001)
+
+        grid0.addWidget(self.simplification_tol_label, 4, 0)
+        grid0.addWidget(self.simplification_tol_spinner, 4, 1)
+        self.ois_simplif = OptionalInputSection(self.simplify_cb,
+                                                [self.simplification_tol_label, self.simplification_tol_spinner],
+                                                logic=True)
 
 
         # Scale Aperture Factor
         # Scale Aperture Factor
         # self.scale_aperture_label = QtWidgets.QLabel(_('Ap. Scale Factor:'))
         # self.scale_aperture_label = QtWidgets.QLabel(_('Ap. Scale Factor:'))
@@ -5141,7 +5161,7 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
         self.update_excellon_cb.setToolTip(
         self.update_excellon_cb.setToolTip(
             "If checked, the Excellon Export settings will be updated with the ones above."
             "If checked, the Excellon Export settings will be updated with the ones above."
         )
         )
-        grid2.addWidget(self.update_excellon_cb, 2, 0)
+        grid2.addWidget(self.update_excellon_cb, 2, 0, 1, 2)
 
 
         grid2.addWidget(QtWidgets.QLabel(""), 3, 0)
         grid2.addWidget(QtWidgets.QLabel(""), 3, 0)
 
 
@@ -5161,8 +5181,10 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
         )
         )
         grid2.addWidget(self.excellon_optimization_label, 5, 0)
         grid2.addWidget(self.excellon_optimization_label, 5, 0)
 
 
-        self.excellon_optimization_radio = RadioSet([{'label': _('MH'), 'value': 'M'},
-                                                     {'label': _('Basic'), 'value': 'B'}])
+        self.excellon_optimization_radio = RadioSet([{'label': _('MetaHeuristic'), 'value': 'M'},
+                                                     {'label': _('Basic'), 'value': 'B'},
+                                                     {'label': _('TSA'), 'value': 'T'}],
+                                                    orientation='vertical', stretch=False)
         self.excellon_optimization_radio.setToolTip(
         self.excellon_optimization_radio.setToolTip(
             _("This sets the optimization type for the Excellon drill path.\n"
             _("This sets the optimization type for the Excellon drill path.\n"
               "If MH is checked then Google OR-Tools algorithm with MetaHeuristic\n"
               "If MH is checked then Google OR-Tools algorithm with MetaHeuristic\n"
@@ -5234,6 +5256,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         grid2 = QtWidgets.QGridLayout()
         grid2 = QtWidgets.QGridLayout()
         self.layout.addLayout(grid2)
         self.layout.addLayout(grid2)
 
 
+        # Cut Z
         cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
         cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
         cutzlabel.setToolTip(
         cutzlabel.setToolTip(
             _("Drill depth (negative)\n"
             _("Drill depth (negative)\n"
@@ -5243,6 +5266,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         self.cutz_entry = LengthEntry()
         self.cutz_entry = LengthEntry()
         grid2.addWidget(self.cutz_entry, 0, 1)
         grid2.addWidget(self.cutz_entry, 0, 1)
 
 
+        # Travel Z
         travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
         travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
         travelzlabel.setToolTip(
         travelzlabel.setToolTip(
             _("Tool height when travelling\n"
             _("Tool height when travelling\n"
@@ -5271,15 +5295,27 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         self.toolchangez_entry = LengthEntry()
         self.toolchangez_entry = LengthEntry()
         grid2.addWidget(self.toolchangez_entry, 3, 1)
         grid2.addWidget(self.toolchangez_entry, 3, 1)
 
 
-        frlabel = QtWidgets.QLabel('%s:' % _('Feedrate (Plunge)'))
+        # End Move Z
+        endzlabel = QtWidgets.QLabel('%s:' % _('End move Z'))
+        endzlabel.setToolTip(
+            _("Height of the tool after\n"
+              "the last move at the end of the job.")
+        )
+        grid2.addWidget(endzlabel, 4, 0)
+        self.eendz_entry = LengthEntry()
+        grid2.addWidget(self.eendz_entry, 4, 1)
+
+        # Feedrate Z
+        frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
         frlabel.setToolTip(
         frlabel.setToolTip(
             _("Tool speed while drilling\n"
             _("Tool speed while drilling\n"
               "(in units per minute).\n"
               "(in units per minute).\n"
+              "So called 'Plunge' feedrate.\n"
               "This is for linear move G01.")
               "This is for linear move G01.")
         )
         )
-        grid2.addWidget(frlabel, 4, 0)
+        grid2.addWidget(frlabel, 5, 0)
         self.feedrate_entry = LengthEntry()
         self.feedrate_entry = LengthEntry()
-        grid2.addWidget(self.feedrate_entry, 4, 1)
+        grid2.addWidget(self.feedrate_entry, 5, 1)
 
 
         # Spindle speed
         # Spindle speed
         spdlabel = QtWidgets.QLabel('%s:' % _('Spindle Speed'))
         spdlabel = QtWidgets.QLabel('%s:' % _('Spindle Speed'))
@@ -5287,23 +5323,9 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
             _("Speed of the spindle\n"
             _("Speed of the spindle\n"
               "in RPM (optional)")
               "in RPM (optional)")
         )
         )
-        grid2.addWidget(spdlabel, 5, 0)
+        grid2.addWidget(spdlabel, 6, 0)
         self.spindlespeed_entry = IntEntry(allow_empty=True)
         self.spindlespeed_entry = IntEntry(allow_empty=True)
-        grid2.addWidget(self.spindlespeed_entry, 5, 1)
-
-        # Spindle direction
-        spindle_dir_label = QtWidgets.QLabel('%s:' % _('Spindle dir.'))
-        spindle_dir_label.setToolTip(
-            _("This sets the direction that the spindle is rotating.\n"
-              "It can be either:\n"
-              "- CW = clockwise or\n"
-              "- CCW = counter clockwise")
-        )
-
-        self.spindledir_radio = RadioSet([{'label': _('CW'), 'value': 'CW'},
-                                          {'label': _('CCW'), 'value': 'CCW'}])
-        grid2.addWidget(spindle_dir_label, 6, 0)
-        grid2.addWidget(self.spindledir_radio, 6, 1)
+        grid2.addWidget(self.spindlespeed_entry, 6, 1)
 
 
         # Dwell
         # Dwell
         dwelllabel = QtWidgets.QLabel('%s:' % _('Dwell'))
         dwelllabel = QtWidgets.QLabel('%s:' % _('Dwell'))
@@ -5317,6 +5339,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         )
         )
         self.dwell_cb = FCCheckBox()
         self.dwell_cb = FCCheckBox()
         self.dwelltime_entry = FCEntry()
         self.dwelltime_entry = FCEntry()
+
         grid2.addWidget(dwelllabel, 7, 0)
         grid2.addWidget(dwelllabel, 7, 0)
         grid2.addWidget(self.dwell_cb, 7, 1)
         grid2.addWidget(self.dwell_cb, 7, 1)
         grid2.addWidget(dwelltime, 8, 0)
         grid2.addWidget(dwelltime, 8, 0)
@@ -5358,7 +5381,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
         self.mill_hole_label.setToolTip(
         self.mill_hole_label.setToolTip(
             _("Create Geometry for milling holes.")
             _("Create Geometry for milling holes.")
         )
         )
-        grid2.addWidget(excellon_gcode_type_label, 11, 0, 1, 2)
+        grid2.addWidget(self.mill_hole_label, 11, 0, 1, 2)
 
 
         tdlabel = QtWidgets.QLabel('%s:' % _('Drill Tool dia'))
         tdlabel = QtWidgets.QLabel('%s:' % _('Drill Tool dia'))
         tdlabel.setToolTip(
         tdlabel.setToolTip(
@@ -5400,12 +5423,13 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
         # ## ADVANCED OPTIONS ###
         # ## ADVANCED OPTIONS ###
         # #######################
         # #######################
 
 
-        self.cncjob_label = QtWidgets.QLabel('<b>%s:</b>' % _('Advanced Options'))
-        self.cncjob_label.setToolTip(
-            _("Parameters used to create a CNC Job object\n"
-              "for this drill object that are shown when App Level is Advanced.")
+        self.exc_label = QtWidgets.QLabel('<b>%s:</b>' % _('Advanced Options'))
+        self.exc_label.setToolTip(
+            _("A list of Excellon advanced parameters.\n"
+              "Those parameters are available only for\n"
+              "Advanced App. Level.")
         )
         )
-        self.layout.addWidget(self.cncjob_label)
+        self.layout.addWidget(self.exc_label)
 
 
         grid1 = QtWidgets.QGridLayout()
         grid1 = QtWidgets.QGridLayout()
         self.layout.addLayout(grid1)
         self.layout.addLayout(grid1)
@@ -5436,15 +5460,7 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
         self.estartz_entry = FloatEntry()
         self.estartz_entry = FloatEntry()
         grid1.addWidget(self.estartz_entry, 2, 1)
         grid1.addWidget(self.estartz_entry, 2, 1)
 
 
-        endzlabel = QtWidgets.QLabel('%s:' % _('End move Z'))
-        endzlabel.setToolTip(
-            _("Height of the tool after\n"
-              "the last move at the end of the job.")
-        )
-        grid1.addWidget(endzlabel, 3, 0)
-        self.eendz_entry = LengthEntry()
-        grid1.addWidget(self.eendz_entry, 3, 1)
-
+        # Feedrate Rapids
         fr_rapid_label = QtWidgets.QLabel('%s:' % _('Feedrate Rapids'))
         fr_rapid_label = QtWidgets.QLabel('%s:' % _('Feedrate Rapids'))
         fr_rapid_label.setToolTip(
         fr_rapid_label.setToolTip(
             _("Tool speed while drilling\n"
             _("Tool speed while drilling\n"
@@ -5453,9 +5469,9 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
               "It is useful only for Marlin,\n"
               "It is useful only for Marlin,\n"
               "ignore for any other cases.")
               "ignore for any other cases.")
         )
         )
-        grid1.addWidget(fr_rapid_label, 4, 0)
+        grid1.addWidget(fr_rapid_label, 3, 0)
         self.feedrate_rapid_entry = LengthEntry()
         self.feedrate_rapid_entry = LengthEntry()
-        grid1.addWidget(self.feedrate_rapid_entry, 4, 1)
+        grid1.addWidget(self.feedrate_rapid_entry, 3, 1)
 
 
         # Probe depth
         # Probe depth
         self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
         self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
@@ -5463,18 +5479,32 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
             _("The maximum depth that the probe is allowed\n"
             _("The maximum depth that the probe is allowed\n"
               "to probe. Negative value, in current units.")
               "to probe. Negative value, in current units.")
         )
         )
-        grid1.addWidget(self.pdepth_label, 5, 0)
+        grid1.addWidget(self.pdepth_label, 4, 0)
         self.pdepth_entry = FCEntry()
         self.pdepth_entry = FCEntry()
-        grid1.addWidget(self.pdepth_entry, 5, 1)
+        grid1.addWidget(self.pdepth_entry, 4, 1)
 
 
         # Probe feedrate
         # Probe feedrate
         self.feedrate_probe_label = QtWidgets.QLabel('%s:' % _("Feedrate Probe"))
         self.feedrate_probe_label = QtWidgets.QLabel('%s:' % _("Feedrate Probe"))
         self.feedrate_probe_label.setToolTip(
         self.feedrate_probe_label.setToolTip(
            _("The feedrate used while the probe is probing.")
            _("The feedrate used while the probe is probing.")
         )
         )
-        grid1.addWidget(self.feedrate_probe_label, 6, 0)
+        grid1.addWidget(self.feedrate_probe_label, 5, 0)
         self.feedrate_probe_entry = FCEntry()
         self.feedrate_probe_entry = FCEntry()
-        grid1.addWidget(self.feedrate_probe_entry, 6, 1)
+        grid1.addWidget(self.feedrate_probe_entry, 5, 1)
+
+        # Spindle direction
+        spindle_dir_label = QtWidgets.QLabel('%s:' % _('Spindle dir.'))
+        spindle_dir_label.setToolTip(
+            _("This sets the direction that the spindle is rotating.\n"
+              "It can be either:\n"
+              "- CW = clockwise or\n"
+              "- CCW = counter clockwise")
+        )
+
+        self.spindledir_radio = RadioSet([{'label': _('CW'), 'value': 'CW'},
+                                          {'label': _('CCW'), 'value': 'CCW'}])
+        grid1.addWidget(spindle_dir_label, 6, 0)
+        grid1.addWidget(self.spindledir_radio, 6, 1)
 
 
         fplungelabel = QtWidgets.QLabel('%s:' % _('Fast Plunge'))
         fplungelabel = QtWidgets.QLabel('%s:' % _('Fast Plunge'))
         fplungelabel.setToolTip(
         fplungelabel.setToolTip(
@@ -6048,15 +6078,25 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
         self.toolchangez_entry = LengthEntry()
         self.toolchangez_entry = LengthEntry()
         grid1.addWidget(self.toolchangez_entry, 5, 1)
         grid1.addWidget(self.toolchangez_entry, 5, 1)
 
 
+        # End move Z
+        endzlabel = QtWidgets.QLabel('%s:' % _('End move Z'))
+        endzlabel.setToolTip(
+            _("Height of the tool after\n"
+              "the last move at the end of the job.")
+        )
+        grid1.addWidget(endzlabel, 6, 0)
+        self.gendz_entry = LengthEntry()
+        grid1.addWidget(self.gendz_entry, 6, 1)
+
         # Feedrate X-Y
         # Feedrate X-Y
         frlabel = QtWidgets.QLabel('%s:' % _('Feed Rate X-Y'))
         frlabel = QtWidgets.QLabel('%s:' % _('Feed Rate X-Y'))
         frlabel.setToolTip(
         frlabel.setToolTip(
             _("Cutting speed in the XY\n"
             _("Cutting speed in the XY\n"
               "plane in units per minute")
               "plane in units per minute")
         )
         )
-        grid1.addWidget(frlabel, 6, 0)
+        grid1.addWidget(frlabel, 7, 0)
         self.cncfeedrate_entry = LengthEntry()
         self.cncfeedrate_entry = LengthEntry()
-        grid1.addWidget(self.cncfeedrate_entry, 6, 1)
+        grid1.addWidget(self.cncfeedrate_entry, 7, 1)
 
 
         # Feedrate Z (Plunge)
         # Feedrate Z (Plunge)
         frz_label = QtWidgets.QLabel('%s:' % _('Feed Rate Z'))
         frz_label = QtWidgets.QLabel('%s:' % _('Feed Rate Z'))
@@ -6065,9 +6105,9 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
               "plane in units per minute.\n"
               "plane in units per minute.\n"
               "It is called also Plunge.")
               "It is called also Plunge.")
         )
         )
-        grid1.addWidget(frz_label, 7, 0)
+        grid1.addWidget(frz_label, 8, 0)
         self.cncplunge_entry = LengthEntry()
         self.cncplunge_entry = LengthEntry()
-        grid1.addWidget(self.cncplunge_entry, 7, 1)
+        grid1.addWidget(self.cncplunge_entry, 8, 1)
 
 
         # Spindle Speed
         # Spindle Speed
         spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed'))
         spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed'))
@@ -6078,23 +6118,9 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
                 "this value is the power of laser."
                 "this value is the power of laser."
             )
             )
         )
         )
-        grid1.addWidget(spdlabel, 8, 0)
+        grid1.addWidget(spdlabel, 9, 0)
         self.cncspindlespeed_entry = IntEntry(allow_empty=True)
         self.cncspindlespeed_entry = IntEntry(allow_empty=True)
-        grid1.addWidget(self.cncspindlespeed_entry, 8, 1)
-
-        # Spindle direction
-        spindle_dir_label = QtWidgets.QLabel('%s:' % _('Spindle dir.'))
-        spindle_dir_label.setToolTip(
-            _("This sets the direction that the spindle is rotating.\n"
-              "It can be either:\n"
-              "- CW = clockwise or\n"
-              "- CCW = counter clockwise")
-        )
-
-        self.spindledir_radio = RadioSet([{'label': _('CW'), 'value': 'CW'},
-                                          {'label': _('CCW'), 'value': 'CCW'}])
-        grid1.addWidget(spindle_dir_label, 9, 0)
-        grid1.addWidget(self.spindledir_radio, 9, 1)
+        grid1.addWidget(self.cncspindlespeed_entry, 9, 1)
 
 
         # Dwell
         # Dwell
         self.dwell_cb = FCCheckBox(label='%s:' % _('Dwell'))
         self.dwell_cb = FCCheckBox(label='%s:' % _('Dwell'))
@@ -6137,12 +6163,13 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
         # ------------------------------
         # ------------------------------
         # ## Advanced Options
         # ## Advanced Options
         # ------------------------------
         # ------------------------------
-        self.cncjob_label = QtWidgets.QLabel('<b>%s:</b>' % _('Advanced Options'))
-        self.cncjob_label.setToolTip(
-            _("Parameters to create a CNC Job object\n"
-              "tracing the contours of a Geometry object.")
+        self.geo_label = QtWidgets.QLabel('<b>%s:</b>' % _('Advanced Options'))
+        self.geo_label.setToolTip(
+            _("A list of Geometry advanced parameters.\n"
+              "Those parameters are available only for\n"
+              "Advanced App. Level.")
         )
         )
-        self.layout.addWidget(self.cncjob_label)
+        self.layout.addWidget(self.geo_label)
 
 
         grid1 = QtWidgets.QGridLayout()
         grid1 = QtWidgets.QGridLayout()
         self.layout.addLayout(grid1)
         self.layout.addLayout(grid1)
@@ -6166,16 +6193,6 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
         self.gstartz_entry = FloatEntry()
         self.gstartz_entry = FloatEntry()
         grid1.addWidget(self.gstartz_entry, 2, 1)
         grid1.addWidget(self.gstartz_entry, 2, 1)
 
 
-        # End move Z
-        endzlabel = QtWidgets.QLabel('%s:' % _('End move Z'))
-        endzlabel.setToolTip(
-            _("Height of the tool after\n"
-              "the last move at the end of the job.")
-        )
-        grid1.addWidget(endzlabel, 3, 0)
-        self.gendz_entry = LengthEntry()
-        grid1.addWidget(self.gendz_entry, 3, 1)
-
         # Feedrate rapids
         # Feedrate rapids
         fr_rapid_label = QtWidgets.QLabel('%s:' % _('Feed Rate Rapids'))
         fr_rapid_label = QtWidgets.QLabel('%s:' % _('Feed Rate Rapids'))
         fr_rapid_label.setToolTip(
         fr_rapid_label.setToolTip(
@@ -6218,6 +6235,20 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
         self.feedrate_probe_entry = FCEntry()
         self.feedrate_probe_entry = FCEntry()
         grid1.addWidget(self.feedrate_probe_entry, 7, 1)
         grid1.addWidget(self.feedrate_probe_entry, 7, 1)
 
 
+        # Spindle direction
+        spindle_dir_label = QtWidgets.QLabel('%s:' % _('Spindle dir.'))
+        spindle_dir_label.setToolTip(
+            _("This sets the direction that the spindle is rotating.\n"
+              "It can be either:\n"
+              "- CW = clockwise or\n"
+              "- CCW = counter clockwise")
+        )
+
+        self.spindledir_radio = RadioSet([{'label': _('CW'), 'value': 'CW'},
+                                          {'label': _('CCW'), 'value': 'CCW'}])
+        grid1.addWidget(spindle_dir_label, 8, 0)
+        grid1.addWidget(self.spindledir_radio, 8, 1)
+
         # Fast Move from Z Toolchange
         # Fast Move from Z Toolchange
         fplungelabel = QtWidgets.QLabel('%s:' % _('Fast Plunge'))
         fplungelabel = QtWidgets.QLabel('%s:' % _('Fast Plunge'))
         fplungelabel.setToolTip(
         fplungelabel.setToolTip(
@@ -6227,8 +6258,8 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
               "WARNING: the move is done at Toolchange X,Y coords.")
               "WARNING: the move is done at Toolchange X,Y coords.")
         )
         )
         self.fplunge_cb = FCCheckBox()
         self.fplunge_cb = FCCheckBox()
-        grid1.addWidget(fplungelabel, 8, 0)
-        grid1.addWidget(self.fplunge_cb, 8, 1)
+        grid1.addWidget(fplungelabel, 9, 0)
+        grid1.addWidget(self.fplunge_cb, 9, 1)
 
 
         # Size of trace segment on X axis
         # Size of trace segment on X axis
         segx_label = QtWidgets.QLabel('%s:' % _("Seg. X size"))
         segx_label = QtWidgets.QLabel('%s:' % _("Seg. X size"))
@@ -6237,9 +6268,9 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
               "Useful for auto-leveling.\n"
               "Useful for auto-leveling.\n"
               "A value of 0 means no segmentation on the X axis.")
               "A value of 0 means no segmentation on the X axis.")
         )
         )
-        grid1.addWidget(segx_label, 9, 0)
+        grid1.addWidget(segx_label, 10, 0)
         self.segx_entry = FCEntry()
         self.segx_entry = FCEntry()
-        grid1.addWidget(self.segx_entry, 9, 1)
+        grid1.addWidget(self.segx_entry, 10, 1)
 
 
         # Size of trace segment on Y axis
         # Size of trace segment on Y axis
         segy_label = QtWidgets.QLabel('%s:' % _("Seg. Y size"))
         segy_label = QtWidgets.QLabel('%s:' % _("Seg. Y size"))
@@ -6248,9 +6279,9 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
               "Useful for auto-leveling.\n"
               "Useful for auto-leveling.\n"
               "A value of 0 means no segmentation on the Y axis.")
               "A value of 0 means no segmentation on the Y axis.")
         )
         )
-        grid1.addWidget(segy_label, 10, 0)
+        grid1.addWidget(segy_label, 11, 0)
         self.segy_entry = FCEntry()
         self.segy_entry = FCEntry()
-        grid1.addWidget(self.segy_entry, 10, 1)
+        grid1.addWidget(self.segy_entry, 11, 1)
 
 
         self.layout.addStretch()
         self.layout.addStretch()
 
 
@@ -6344,37 +6375,6 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
         grid0.addWidget(self.annotation_cb, 2, 1)
         grid0.addWidget(self.annotation_cb, 2, 1)
         grid0.addWidget(QtWidgets.QLabel(''), 2, 2)
         grid0.addWidget(QtWidgets.QLabel(''), 2, 2)
 
 
-        # Annotation Font Size
-        self.annotation_fontsize_label = QtWidgets.QLabel('%s:' % _("Annotation Size"))
-        self.annotation_fontsize_label.setToolTip(
-            _("The font size of the annotation text. In pixels.")
-        )
-        grid0.addWidget(self.annotation_fontsize_label, 3, 0)
-        self.annotation_fontsize_sp = FCSpinner()
-        grid0.addWidget(self.annotation_fontsize_sp, 3, 1)
-        grid0.addWidget(QtWidgets.QLabel(''), 3, 2)
-
-        # Annotation Font Color
-        self.annotation_color_label = QtWidgets.QLabel('%s:' % _('Annotation Color'))
-        self.annotation_color_label.setToolTip(
-            _("Set the font color for the annotation texts.")
-        )
-        self.annotation_fontcolor_entry = FCEntry()
-        self.annotation_fontcolor_button = QtWidgets.QPushButton()
-        self.annotation_fontcolor_button.setFixedSize(15, 15)
-
-        self.form_box_child = QtWidgets.QHBoxLayout()
-        self.form_box_child.setContentsMargins(0, 0, 0, 0)
-        self.form_box_child.addWidget(self.annotation_fontcolor_entry)
-        self.form_box_child.addWidget(self.annotation_fontcolor_button, alignment=Qt.AlignRight)
-        self.form_box_child.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
-
-        color_widget = QtWidgets.QWidget()
-        color_widget.setLayout(self.form_box_child)
-        grid0.addWidget(self.annotation_color_label, 4, 0)
-        grid0.addWidget(color_widget, 4, 1)
-        grid0.addWidget(QtWidgets.QLabel(''), 4, 2)
-
         # ###################################################################
         # ###################################################################
         # Number of circle steps for circular aperture linear approximation #
         # Number of circle steps for circular aperture linear approximation #
         # ###################################################################
         # ###################################################################
@@ -6383,9 +6383,9 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
             _("The number of circle steps for <b>GCode</b> \n"
             _("The number of circle steps for <b>GCode</b> \n"
               "circle and arc shapes linear approximation.")
               "circle and arc shapes linear approximation.")
         )
         )
-        grid0.addWidget(self.steps_per_circle_label, 5, 0)
+        grid0.addWidget(self.steps_per_circle_label, 3, 0)
         self.steps_per_circle_entry = IntEntry()
         self.steps_per_circle_entry = IntEntry()
-        grid0.addWidget(self.steps_per_circle_entry, 5, 1)
+        grid0.addWidget(self.steps_per_circle_entry, 3, 1)
 
 
         # Tool dia for plot
         # Tool dia for plot
         tdlabel = QtWidgets.QLabel('%s:' % _('Travel dia'))
         tdlabel = QtWidgets.QLabel('%s:' % _('Travel dia'))
@@ -6394,11 +6394,11 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
               "rendered in the plot.")
               "rendered in the plot.")
         )
         )
         self.tooldia_entry = LengthEntry()
         self.tooldia_entry = LengthEntry()
-        grid0.addWidget(tdlabel, 6, 0)
-        grid0.addWidget(self.tooldia_entry, 6, 1)
+        grid0.addWidget(tdlabel, 4, 0)
+        grid0.addWidget(self.tooldia_entry, 4, 1)
 
 
         # add a space
         # add a space
-        grid0.addWidget(QtWidgets.QLabel(''), 7, 0)
+        grid0.addWidget(QtWidgets.QLabel(''), 5, 0)
 
 
         # Number of decimals to use in GCODE coordinates
         # Number of decimals to use in GCODE coordinates
         cdeclabel = QtWidgets.QLabel('%s:' % _('Coordinates decimals'))
         cdeclabel = QtWidgets.QLabel('%s:' % _('Coordinates decimals'))
@@ -6407,8 +6407,8 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
               "the X, Y, Z coordinates in CNC code (GCODE, etc.)")
               "the X, Y, Z coordinates in CNC code (GCODE, etc.)")
         )
         )
         self.coords_dec_entry = IntEntry()
         self.coords_dec_entry = IntEntry()
-        grid0.addWidget(cdeclabel, 8, 0)
-        grid0.addWidget(self.coords_dec_entry, 8, 1)
+        grid0.addWidget(cdeclabel, 6, 0)
+        grid0.addWidget(self.coords_dec_entry, 6, 1)
 
 
         # Number of decimals to use in GCODE feedrate
         # Number of decimals to use in GCODE feedrate
         frdeclabel = QtWidgets.QLabel('%s:' % _('Feedrate decimals'))
         frdeclabel = QtWidgets.QLabel('%s:' % _('Feedrate decimals'))
@@ -6417,8 +6417,8 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
               "the Feedrate parameter in CNC code (GCODE, etc.)")
               "the Feedrate parameter in CNC code (GCODE, etc.)")
         )
         )
         self.fr_dec_entry = IntEntry()
         self.fr_dec_entry = IntEntry()
-        grid0.addWidget(frdeclabel, 9, 0)
-        grid0.addWidget(self.fr_dec_entry, 9, 1)
+        grid0.addWidget(frdeclabel, 7, 0)
+        grid0.addWidget(self.fr_dec_entry, 7, 1)
 
 
         # The type of coordinates used in the Gcode: Absolute or Incremental
         # The type of coordinates used in the Gcode: Absolute or Incremental
         coords_type_label = QtWidgets.QLabel('%s:' % _('Coordinates type'))
         coords_type_label = QtWidgets.QLabel('%s:' % _('Coordinates type'))
@@ -6432,8 +6432,8 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
             {"label": _("Absolute G90"), "value": "G90"},
             {"label": _("Absolute G90"), "value": "G90"},
             {"label": _("Incremental G91"), "value": "G91"}
             {"label": _("Incremental G91"), "value": "G91"}
         ], orientation='vertical', stretch=False)
         ], orientation='vertical', stretch=False)
-        grid0.addWidget(coords_type_label, 10, 0)
-        grid0.addWidget(self.coords_type_radio, 10, 1)
+        grid0.addWidget(coords_type_label, 8, 0)
+        grid0.addWidget(self.coords_type_radio, 8, 1)
 
 
         # hidden for the time being, until implemented
         # hidden for the time being, until implemented
         coords_type_label.hide()
         coords_type_label.hide()
@@ -6570,6 +6570,42 @@ class CNCJobAdvOptPrefGroupUI(OptionsGroupUI):
         # )
         # )
         # hlay1.addWidget(self.tc_insert_buton)
         # hlay1.addWidget(self.tc_insert_buton)
 
 
+        grid0 = QtWidgets.QGridLayout()
+        self.layout.addLayout(grid0)
+
+        grid0.addWidget(QtWidgets.QLabel(''), 1, 0, 1, 2)
+
+        # Annotation Font Size
+        self.annotation_fontsize_label = QtWidgets.QLabel('%s:' % _("Annotation Size"))
+        self.annotation_fontsize_label.setToolTip(
+            _("The font size of the annotation text. In pixels.")
+        )
+        grid0.addWidget(self.annotation_fontsize_label, 2, 0)
+        self.annotation_fontsize_sp = FCSpinner()
+        grid0.addWidget(self.annotation_fontsize_sp, 2, 1)
+        grid0.addWidget(QtWidgets.QLabel(''), 2, 2)
+
+        # Annotation Font Color
+        self.annotation_color_label = QtWidgets.QLabel('%s:' % _('Annotation Color'))
+        self.annotation_color_label.setToolTip(
+            _("Set the font color for the annotation texts.")
+        )
+        self.annotation_fontcolor_entry = FCEntry()
+        self.annotation_fontcolor_button = QtWidgets.QPushButton()
+        self.annotation_fontcolor_button.setFixedSize(15, 15)
+
+        self.form_box_child = QtWidgets.QHBoxLayout()
+        self.form_box_child.setContentsMargins(0, 0, 0, 0)
+        self.form_box_child.addWidget(self.annotation_fontcolor_entry)
+        self.form_box_child.addWidget(self.annotation_fontcolor_button, alignment=Qt.AlignRight)
+        self.form_box_child.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+
+        color_widget = QtWidgets.QWidget()
+        color_widget.setLayout(self.form_box_child)
+        grid0.addWidget(self.annotation_color_label, 3, 0)
+        grid0.addWidget(color_widget, 3, 1)
+        grid0.addWidget(QtWidgets.QLabel(''), 3, 2)
+
         self.layout.addStretch()
         self.layout.addStretch()
 
 
 
 
@@ -6705,8 +6741,12 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
              "Higher values = slow processing and slow execution on CNC\n"
              "Higher values = slow processing and slow execution on CNC\n"
              "due of too many paths.")
              "due of too many paths.")
         )
         )
+        self.ncc_overlap_entry = FCDoubleSpinner()
+        self.ncc_overlap_entry.set_precision(3)
+        self.ncc_overlap_entry.setWrapping(True)
+        self.ncc_overlap_entry.setRange(0.000, 0.999)
+        self.ncc_overlap_entry.setSingleStep(0.1)
         grid0.addWidget(nccoverlabel, 7, 0)
         grid0.addWidget(nccoverlabel, 7, 0)
-        self.ncc_overlap_entry = FloatEntry()
         grid0.addWidget(self.ncc_overlap_entry, 7, 1)
         grid0.addWidget(self.ncc_overlap_entry, 7, 1)
 
 
         # Margin entry
         # Margin entry
@@ -7050,8 +7090,12 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
               "Higher values = slow processing and slow execution on CNC\n"
               "Higher values = slow processing and slow execution on CNC\n"
               "due of too many paths.")
               "due of too many paths.")
         )
         )
+        self.paintoverlap_entry = FCDoubleSpinner()
+        self.paintoverlap_entry.set_precision(3)
+        self.paintoverlap_entry.setWrapping(True)
+        self.paintoverlap_entry.setRange(0.000, 0.999)
+        self.paintoverlap_entry.setSingleStep(0.1)
         grid0.addWidget(ovlabel, 2, 0)
         grid0.addWidget(ovlabel, 2, 0)
-        self.paintoverlap_entry = LengthEntry()
         grid0.addWidget(self.paintoverlap_entry, 2, 1)
         grid0.addWidget(self.paintoverlap_entry, 2, 1)
 
 
         # Margin
         # Margin
@@ -7167,6 +7211,26 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
         grid0.addWidget(ftypelbl, 0, 0)
         grid0.addWidget(ftypelbl, 0, 0)
         grid0.addWidget(self.film_type_radio, 0, 1)
         grid0.addWidget(self.film_type_radio, 0, 1)
 
 
+        # Film Color
+        self.film_color_label = QtWidgets.QLabel('%s:' % _('Film Color'))
+        self.film_color_label.setToolTip(
+            _("Set the film color when positive film is selected.")
+        )
+        self.film_color_entry = FCEntry()
+        self.film_color_button = QtWidgets.QPushButton()
+        self.film_color_button.setFixedSize(15, 15)
+
+        self.form_box_child = QtWidgets.QHBoxLayout()
+        self.form_box_child.setContentsMargins(0, 0, 0, 0)
+        self.form_box_child.addWidget(self.film_color_entry)
+        self.form_box_child.addWidget(self.film_color_button, alignment=Qt.AlignRight)
+        self.form_box_child.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+
+        film_color_widget = QtWidgets.QWidget()
+        film_color_widget.setLayout(self.form_box_child)
+        grid0.addWidget(self.film_color_label, 1, 0)
+        grid0.addWidget(film_color_widget, 1, 1)
+
         self.film_boundary_entry = FCEntry()
         self.film_boundary_entry = FCEntry()
         self.film_boundary_label = QtWidgets.QLabel('%s:' % _("Border"))
         self.film_boundary_label = QtWidgets.QLabel('%s:' % _("Border"))
         self.film_boundary_label.setToolTip(
         self.film_boundary_label.setToolTip(
@@ -7179,8 +7243,8 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
               "white color like the rest and which may confound with the\n"
               "white color like the rest and which may confound with the\n"
               "surroundings if not for this border.")
               "surroundings if not for this border.")
         )
         )
-        grid0.addWidget(self.film_boundary_label, 1, 0)
-        grid0.addWidget(self.film_boundary_entry, 1, 1)
+        grid0.addWidget(self.film_boundary_label, 2, 0)
+        grid0.addWidget(self.film_boundary_entry, 2, 1)
 
 
         self.film_scale_entry = FCEntry()
         self.film_scale_entry = FCEntry()
         self.film_scale_label = QtWidgets.QLabel('%s:' % _("Scale Stroke"))
         self.film_scale_label = QtWidgets.QLabel('%s:' % _("Scale Stroke"))
@@ -7189,8 +7253,8 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
               "It means that the line that envelope each SVG feature will be thicker or thinner,\n"
               "It means that the line that envelope each SVG feature will be thicker or thinner,\n"
               "therefore the fine features may be more affected by this parameter.")
               "therefore the fine features may be more affected by this parameter.")
         )
         )
-        grid0.addWidget(self.film_scale_label, 2, 0)
-        grid0.addWidget(self.film_scale_entry, 2, 1)
+        grid0.addWidget(self.film_scale_label, 3, 0)
+        grid0.addWidget(self.film_scale_entry, 3, 1)
 
 
         self.layout.addStretch()
         self.layout.addStretch()
 
 
@@ -7737,7 +7801,7 @@ class FAExcPrefGroupUI(OptionsGroupUI):
         self.layout.addWidget(self.exc_list_label)
         self.layout.addWidget(self.exc_list_label)
 
 
         self.exc_list_text = FCTextArea()
         self.exc_list_text = FCTextArea()
-        self.exc_list_text.sizeHint(custom_sizehint=150)
+        # self.exc_list_text.sizeHint(custom_sizehint=150)
         font = QtGui.QFont()
         font = QtGui.QFont()
         font.setPointSize(12)
         font.setPointSize(12)
         self.exc_list_text.setFont(font)
         self.exc_list_text.setFont(font)
@@ -7770,7 +7834,7 @@ class FAGcoPrefGroupUI(OptionsGroupUI):
         self.layout.addWidget(self.gco_list_label)
         self.layout.addWidget(self.gco_list_label)
 
 
         self.gco_list_text = FCTextArea()
         self.gco_list_text = FCTextArea()
-        self.gco_list_text.sizeHint(custom_sizehint=150)
+        # self.gco_list_text.sizeHint(custom_sizehint=150)
         font = QtGui.QFont()
         font = QtGui.QFont()
         font.setPointSize(12)
         font.setPointSize(12)
         self.gco_list_text.setFont(font)
         self.gco_list_text.setFont(font)
@@ -7803,7 +7867,7 @@ class FAGrbPrefGroupUI(OptionsGroupUI):
         self.layout.addWidget(self.grb_list_label)
         self.layout.addWidget(self.grb_list_label)
 
 
         self.grb_list_text = FCTextArea()
         self.grb_list_text = FCTextArea()
-        self.grb_list_text.sizeHint(custom_sizehint=150)
+        # self.grb_list_text.sizeHint(custom_sizehint=150)
         self.layout.addWidget(self.grb_list_text)
         self.layout.addWidget(self.grb_list_text)
         font = QtGui.QFont()
         font = QtGui.QFont()
         font.setPointSize(12)
         font.setPointSize(12)
@@ -7814,6 +7878,7 @@ class FAGrbPrefGroupUI(OptionsGroupUI):
                                        "FlatCAM and the files with above extensions.\n"
                                        "FlatCAM and the files with above extensions.\n"
                                        "They will be active after next logon.\n"
                                        "They will be active after next logon.\n"
                                        "This work only in Windows."))
                                        "This work only in Windows."))
+
         self.layout.addWidget(self.grb_list_btn)
         self.layout.addWidget(self.grb_list_btn)
 
 
         # self.layout.addStretch()
         # self.layout.addStretch()

+ 8 - 3
flatcamGUI/ObjectUI.py

@@ -292,7 +292,11 @@ class GerberObjectUI(ObjectUI):
               "A value here of 0.25 means an overlap of 25%% from the tool diameter found above.")
               "A value here of 0.25 means an overlap of 25%% from the tool diameter found above.")
         )
         )
         overlabel.setMinimumWidth(90)
         overlabel.setMinimumWidth(90)
-        self.iso_overlap_entry = FloatEntry()
+        self.iso_overlap_entry = FCDoubleSpinner()
+        self.iso_overlap_entry.set_precision(3)
+        self.iso_overlap_entry.setWrapping(True)
+        self.iso_overlap_entry.setRange(0.000, 0.999)
+        self.iso_overlap_entry.setSingleStep(0.1)
         grid1.addWidget(overlabel, 2, 0)
         grid1.addWidget(overlabel, 2, 0)
         grid1.addWidget(self.iso_overlap_entry, 2, 1, 1, 2)
         grid1.addWidget(self.iso_overlap_entry, 2, 1, 1, 2)
 
 
@@ -709,11 +713,12 @@ class ExcellonObjectUI(ObjectUI):
         self.eendz_entry = LengthEntry()
         self.eendz_entry = LengthEntry()
         grid1.addWidget(self.eendz_entry, 5, 1)
         grid1.addWidget(self.eendz_entry, 5, 1)
 
 
-        # Excellon Feedrate
-        frlabel = QtWidgets.QLabel('%s:' % _('Feedrate (Plunge)'))
+        # Excellon Feedrate Z
+        frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
         frlabel.setToolTip(
         frlabel.setToolTip(
             _("Tool speed while drilling\n"
             _("Tool speed while drilling\n"
               "(in units per minute).\n"
               "(in units per minute).\n"
+              "So called 'Plunge' feedrate.\n"
               "This is for linear move G01.")
               "This is for linear move G01.")
         )
         )
         grid1.addWidget(frlabel, 6, 0)
         grid1.addWidget(frlabel, 6, 0)

+ 1 - 1
flatcamTools/ToolFilm.py

@@ -274,7 +274,7 @@ class Film(FlatCAMTool):
                 self.app.inform.emit('[WARNING_NOTCL] %s' % _("Export SVG positive cancelled."))
                 self.app.inform.emit('[WARNING_NOTCL] %s' % _("Export SVG positive cancelled."))
                 return
                 return
             else:
             else:
-                self.app.export_svg_black(name, boxname, filename, scale_factor=scale_stroke_width)
+                self.app.export_svg_positive(name, boxname, filename, scale_factor=scale_stroke_width)
         else:
         else:
             try:
             try:
                 filename, _f = QtWidgets.QFileDialog.getSaveFileName(
                 filename, _f = QtWidgets.QFileDialog.getSaveFileName(

+ 8 - 3
flatcamTools/ToolNonCopperClear.py

@@ -292,7 +292,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
               "Higher values = slow processing and slow execution on CNC\n"
               "Higher values = slow processing and slow execution on CNC\n"
               "due of too many paths.")
               "due of too many paths.")
         )
         )
-        self.ncc_overlap_entry = FCEntry()
+        self.ncc_overlap_entry = FCDoubleSpinner()
+        self.ncc_overlap_entry.set_precision(3)
+        self.ncc_overlap_entry.setWrapping(True)
+        self.ncc_overlap_entry.setRange(0.000, 0.999)
+        self.ncc_overlap_entry.setSingleStep(0.1)
         grid3.addWidget(nccoverlabel, 2, 0)
         grid3.addWidget(nccoverlabel, 2, 0)
         grid3.addWidget(self.ncc_overlap_entry, 2, 1)
         grid3.addWidget(self.ncc_overlap_entry, 2, 1)
 
 
@@ -1292,6 +1296,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
                      method=None,
                      method=None,
                      rest=None,
                      rest=None,
                      tools_storage=None,
                      tools_storage=None,
+                     plot=True,
                      run_threaded=True):
                      run_threaded=True):
         """
         """
         Clear the excess copper from the entire object.
         Clear the excess copper from the entire object.
@@ -2189,9 +2194,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
         def job_thread(app_obj):
         def job_thread(app_obj):
             try:
             try:
                 if rest_machining_choice is True:
                 if rest_machining_choice is True:
-                    app_obj.new_object("geometry", name, gen_clear_area_rest)
+                    app_obj.new_object("geometry", name, gen_clear_area_rest, plot=plot)
                 else:
                 else:
-                    app_obj.new_object("geometry", name, gen_clear_area)
+                    app_obj.new_object("geometry", name, gen_clear_area, plot=plot)
             except FlatCAMApp.GracefulException:
             except FlatCAMApp.GracefulException:
                 proc.done()
                 proc.done()
                 return
                 return

+ 40 - 17
flatcamTools/ToolPaint.py

@@ -214,8 +214,12 @@ class ToolPaint(FlatCAMTool, Gerber):
               "Higher values = slow processing and slow execution on CNC\n"
               "Higher values = slow processing and slow execution on CNC\n"
               "due of too many paths.")
               "due of too many paths.")
         )
         )
+        self.paintoverlap_entry = FCDoubleSpinner()
+        self.paintoverlap_entry.set_precision(3)
+        self.paintoverlap_entry.setWrapping(True)
+        self.paintoverlap_entry.setRange(0.000, 0.999)
+        self.paintoverlap_entry.setSingleStep(0.1)
         grid3.addWidget(ovlabel, 1, 0)
         grid3.addWidget(ovlabel, 1, 0)
-        self.paintoverlap_entry = FCEntry()
         grid3.addWidget(self.paintoverlap_entry, 1, 1)
         grid3.addWidget(self.paintoverlap_entry, 1, 1)
 
 
         # Margin
         # Margin
@@ -1168,7 +1172,9 @@ class ToolPaint(FlatCAMTool, Gerber):
                    outname=None,
                    outname=None,
                    connect=None,
                    connect=None,
                    contour=None,
                    contour=None,
-                   tools_storage=None):
+                   tools_storage=None,
+                   plot=True,
+                   run_threaded=True):
         """
         """
         Paints a polygon selected by clicking on its interior or by having a point coordinates given
         Paints a polygon selected by clicking on its interior or by having a point coordinates given
 
 
@@ -1432,7 +1438,7 @@ class ToolPaint(FlatCAMTool, Gerber):
 
 
         def job_thread(app_obj):
         def job_thread(app_obj):
             try:
             try:
-                app_obj.new_object("geometry", name, gen_paintarea)
+                app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
             except FlatCAMApp.GracefulException:
             except FlatCAMApp.GracefulException:
                 proc.done()
                 proc.done()
                 return
                 return
@@ -1451,8 +1457,11 @@ class ToolPaint(FlatCAMTool, Gerber):
         # Promise object with the new name
         # Promise object with the new name
         self.app.collection.promise(name)
         self.app.collection.promise(name)
 
 
-        # Background
-        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        if run_threaded:
+            # Background
+            self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        else:
+            job_thread(app_obj=self.app)
 
 
     def paint_poly_all(self, obj,
     def paint_poly_all(self, obj,
                        tooldia=None,
                        tooldia=None,
@@ -1463,7 +1472,9 @@ class ToolPaint(FlatCAMTool, Gerber):
                        outname=None,
                        outname=None,
                        connect=None,
                        connect=None,
                        contour=None,
                        contour=None,
-                       tools_storage=None):
+                       tools_storage=None,
+                       plot=True,
+                       run_threaded=True):
         """
         """
         Paints all polygons in this object.
         Paints all polygons in this object.
 
 
@@ -1901,9 +1912,9 @@ class ToolPaint(FlatCAMTool, Gerber):
         def job_thread(app_obj):
         def job_thread(app_obj):
             try:
             try:
                 if self.rest_cb.isChecked():
                 if self.rest_cb.isChecked():
-                    app_obj.new_object("geometry", name, gen_paintarea_rest_machining)
+                    app_obj.new_object("geometry", name, gen_paintarea_rest_machining, plot=plot)
                 else:
                 else:
-                    app_obj.new_object("geometry", name, gen_paintarea)
+                    app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
             except FlatCAMApp.GracefulException:
             except FlatCAMApp.GracefulException:
                 proc.done()
                 proc.done()
                 return
                 return
@@ -1920,8 +1931,11 @@ class ToolPaint(FlatCAMTool, Gerber):
         # Promise object with the new name
         # Promise object with the new name
         self.app.collection.promise(name)
         self.app.collection.promise(name)
 
 
-        # Background
-        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        if run_threaded:
+            # Background
+            self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        else:
+            job_thread(app_obj=self.app)
 
 
     def paint_poly_area(self, obj, sel_obj,
     def paint_poly_area(self, obj, sel_obj,
                         tooldia=None,
                         tooldia=None,
@@ -1932,7 +1946,9 @@ class ToolPaint(FlatCAMTool, Gerber):
                         outname=None,
                         outname=None,
                         connect=None,
                         connect=None,
                         contour=None,
                         contour=None,
-                        tools_storage=None):
+                        tools_storage=None,
+                        plot=True,
+                        run_threaded=True):
         """
         """
         Paints all polygons in this object that are within the sel_obj object
         Paints all polygons in this object that are within the sel_obj object
 
 
@@ -2366,9 +2382,9 @@ class ToolPaint(FlatCAMTool, Gerber):
         def job_thread(app_obj):
         def job_thread(app_obj):
             try:
             try:
                 if self.rest_cb.isChecked():
                 if self.rest_cb.isChecked():
-                    app_obj.new_object("geometry", name, gen_paintarea_rest_machining)
+                    app_obj.new_object("geometry", name, gen_paintarea_rest_machining, plot=plot)
                 else:
                 else:
-                    app_obj.new_object("geometry", name, gen_paintarea)
+                    app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
             except FlatCAMApp.GracefulException:
             except FlatCAMApp.GracefulException:
                 proc.done()
                 proc.done()
                 return
                 return
@@ -2385,8 +2401,11 @@ class ToolPaint(FlatCAMTool, Gerber):
         # Promise object with the new name
         # Promise object with the new name
         self.app.collection.promise(name)
         self.app.collection.promise(name)
 
 
-        # Background
-        self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        if run_threaded:
+            # Background
+            self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
+        else:
+            job_thread(app_obj=self.app)
 
 
     def paint_poly_ref(self, obj, sel_obj,
     def paint_poly_ref(self, obj, sel_obj,
                        tooldia=None,
                        tooldia=None,
@@ -2397,7 +2416,9 @@ class ToolPaint(FlatCAMTool, Gerber):
                        outname=None,
                        outname=None,
                        connect=None,
                        connect=None,
                        contour=None,
                        contour=None,
-                       tools_storage=None):
+                       tools_storage=None,
+                       plot=True,
+                       run_threaded=True):
         """
         """
         Paints all polygons in this object that are within the sel_obj object
         Paints all polygons in this object that are within the sel_obj object
 
 
@@ -2441,7 +2462,9 @@ class ToolPaint(FlatCAMTool, Gerber):
                              outname=outname,
                              outname=outname,
                              connect=connect,
                              connect=connect,
                              contour=contour,
                              contour=contour,
-                             tools_storage=tools_storage)
+                             tools_storage=tools_storage,
+                             plot=plot,
+                             run_threaded=run_threaded)
 
 
     @staticmethod
     @staticmethod
     def paint_bounds(geometry):
     def paint_bounds(geometry):

BIN
share/bug16.png


BIN
share/bug32.png


BIN
share/pdf_link16.png


+ 28 - 30
tclCommands/TclCommand.py

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

+ 13 - 7
tclCommands/TclCommandAlignDrill.py

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

+ 11 - 5
tclCommands/TclCommandAlignDrillGrid.py

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

+ 1 - 1
tclCommands/TclCommandBbox.py

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

+ 30 - 12
tclCommands/TclCommandCncjob.py

@@ -24,7 +24,7 @@ class TclCommandCncjob(TclCommandSignaled):
 
 
     # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
     # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
     option_types = collections.OrderedDict([
     option_types = collections.OrderedDict([
-        ('tooldia', float),
+        ('dia', float),
         ('z_cut', float),
         ('z_cut', float),
         ('z_move', float),
         ('z_move', float),
         ('feedrate', float),
         ('feedrate', float),
@@ -42,6 +42,7 @@ class TclCommandCncjob(TclCommandSignaled):
         ('dwell', bool),
         ('dwell', bool),
         ('dwelltime', float),
         ('dwelltime', float),
         ('pp', str),
         ('pp', str),
+        ('muted', int),
         ('outname', str)
         ('outname', str)
     ])
     ])
 
 
@@ -53,7 +54,7 @@ class TclCommandCncjob(TclCommandSignaled):
         'main': "Generates a CNC Job from a Geometry Object.",
         'main': "Generates a CNC Job from a Geometry Object.",
         'args': collections.OrderedDict([
         'args': collections.OrderedDict([
             ('name', 'Name of the source object.'),
             ('name', 'Name of the source object.'),
-            ('tooldia', 'Tool diameter to show on screen.'),
+            ('dia', 'Tool diameter to show on screen.'),
             ('z_cut', 'Z-axis cutting position.'),
             ('z_cut', 'Z-axis cutting position.'),
             ('z_move', 'Z-axis moving position.'),
             ('z_move', 'Z-axis moving position.'),
             ('feedrate', 'Moving speed on X-Y plane when cutting.'),
             ('feedrate', 'Moving speed on X-Y plane when cutting.'),
@@ -71,7 +72,8 @@ class TclCommandCncjob(TclCommandSignaled):
             ('dwell', 'True or False; use (or not) the dwell'),
             ('dwell', 'True or False; use (or not) the dwell'),
             ('dwelltime', 'Time to pause to allow the spindle to reach the full speed'),
             ('dwelltime', 'Time to pause to allow the spindle to reach the full speed'),
             ('outname', 'Name of the resulting Geometry object.'),
             ('outname', 'Name of the resulting Geometry object.'),
-            ('pp', 'Name of the Geometry postprocessor. No quotes, case sensitive')
+            ('pp', 'Name of the Geometry postprocessor. No quotes, case sensitive'),
+            ('muted', 'It will not put errors in the Shell.')
         ]),
         ]),
         'examples': ['cncjob geo_name -tooldia 0.5 -z_cut -1.7 -z_move 2 -feedrate 120 -ppname_g default']
         'examples': ['cncjob geo_name -tooldia 0.5 -z_cut -1.7 -z_move 2 -feedrate 120 -ppname_g default']
     }
     }
@@ -91,15 +93,26 @@ class TclCommandCncjob(TclCommandSignaled):
         if 'outname' not in args:
         if 'outname' not in args:
             args['outname'] = str(name) + "_cnc"
             args['outname'] = str(name) + "_cnc"
 
 
+        if 'muted' in args:
+            muted = args['muted']
+        else:
+            muted = 0
+
         obj = self.app.collection.get_by_name(str(name), isCaseSensitive=False)
         obj = self.app.collection.get_by_name(str(name), isCaseSensitive=False)
 
 
         if obj is None:
         if obj is None:
-            self.raise_tcl_error("Object not found: %s" % str(name))
+            if not muted:
+                self.raise_tcl_error("Object not found: %s" % str(name))
+            else:
+                return
 
 
         if not isinstance(obj, FlatCAMGeometry):
         if not isinstance(obj, FlatCAMGeometry):
-            self.raise_tcl_error('Expected FlatCAMGeometry, got %s %s.' % (str(name), type(obj)))
+            if not muted:
+                self.raise_tcl_error('Expected FlatCAMGeometry, got %s %s.' % (str(name), type(obj)))
+            else:
+                return
 
 
-        args["tooldia"] = args["tooldia"] if "tooldia" in args else obj.options["cnctooldia"]
+        args["dia"] = args["dia"] if "dia" in args else obj.options["cnctooldia"]
 
 
         args["z_cut"] = args["z_cut"] if "z_cut" in args else obj.options["cutz"]
         args["z_cut"] = args["z_cut"] if "z_cut" in args else obj.options["cutz"]
         args["z_move"] = args["z_move"] if "z_move" in args else obj.options["travelz"]
         args["z_move"] = args["z_move"] if "z_move" in args else obj.options["travelz"]
@@ -130,20 +143,24 @@ class TclCommandCncjob(TclCommandSignaled):
         del args['name']
         del args['name']
 
 
         for arg in args:
         for arg in args:
-            if arg == "toolchange_xy" or arg == "spindlespeed":
+            if arg == "toolchange_xy" or arg == "spindlespeed" or arg == "startz":
                 continue
                 continue
             else:
             else:
                 if args[arg] is None:
                 if args[arg] is None:
-                    self.raise_tcl_error('One of the command parameters that have to be not None, is None.\n'
-                                         'The parameter that is None is in the default values found in the list \n'
-                                         'generated by the TclCommand "list_sys geom". or in the arguments.')
+                    print(arg, args[arg])
+                    if not muted:
+                        self.raise_tcl_error('One of the command parameters that have to be not None, is None.\n'
+                                             'The parameter that is None is in the default values found in the list \n'
+                                             'generated by the TclCommand "list_sys geom". or in the arguments.')
+                    else:
+                        return
 
 
         # HACK !!! Should be solved elsewhere!!!
         # HACK !!! Should be solved elsewhere!!!
         # default option for multidepth is False
         # default option for multidepth is False
         obj.options['multidepth'] = False
         obj.options['multidepth'] = False
 
 
         if not obj.multigeo:
         if not obj.multigeo:
-            obj.generatecncjob(use_thread=False, **args)
+            obj.generatecncjob(use_thread=False, plot=False, **args)
         else:
         else:
             # Update the local_tools_dict values with the args value
             # Update the local_tools_dict values with the args value
             local_tools_dict = deepcopy(obj.tools)
             local_tools_dict = deepcopy(obj.tools)
@@ -171,5 +188,6 @@ class TclCommandCncjob(TclCommandSignaled):
                 outname=args['outname'],
                 outname=args['outname'],
                 tools_dict=local_tools_dict,
                 tools_dict=local_tools_dict,
                 tools_in_use=[],
                 tools_in_use=[],
-                use_thread=False)
+                use_thread=False,
+                plot=False)
             # self.raise_tcl_error('The object is a multi-geo geometry which is not supported in cncjob Tcl Command')
             # self.raise_tcl_error('The object is a multi-geo geometry which is not supported in cncjob Tcl Command')

+ 2 - 0
tclCommands/TclCommandCopperClear.py

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

+ 1 - 1
tclCommands/TclCommandCutout.py

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

+ 19 - 7
tclCommands/TclCommandDrillcncjob.py

@@ -17,7 +17,6 @@ class TclCommandDrillcncjob(TclCommandSignaled):
 
 
     # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
     # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
     option_types = collections.OrderedDict([
     option_types = collections.OrderedDict([
-        ('tools', str),
         ('drilled_dias', str),
         ('drilled_dias', str),
         ('drillz', float),
         ('drillz', float),
         ('travelz', float),
         ('travelz', float),
@@ -31,7 +30,8 @@ class TclCommandDrillcncjob(TclCommandSignaled):
         ('pp', str),
         ('pp', str),
         ('outname', str),
         ('outname', str),
         ('opt_type', str),
         ('opt_type', str),
-        ('diatol', float)
+        ('diatol', float),
+        ('muted', int)
     ])
     ])
 
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
     # array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -62,7 +62,8 @@ class TclCommandDrillcncjob(TclCommandSignaled):
                        'the same as the ones in the tools from the Excellon object. E.g: if in drill_dias we have a '
                        'the same as the ones in the tools from the Excellon object. E.g: if in drill_dias we have a '
                        'diameter with value 1.0, in the Excellon we have a tool with dia = 1.05 and we set a tolerance '
                        'diameter with value 1.0, in the Excellon we have a tool with dia = 1.05 and we set a tolerance '
                        'diatol = 5.0 then the drills with the dia = (0.95 ... 1.05) '
                        'diatol = 5.0 then the drills with the dia = (0.95 ... 1.05) '
-                       'in Excellon will be processed. Float number.')
+                       'in Excellon will be processed. Float number.'),
+            ('muted', 'It will not put errors in the Shell or status bar.')
         ]),
         ]),
         'examples': ['drillcncjob test.TXT -drillz -1.5 -travelz 14 -feedrate 222 -feedrate_rapid 456 -spindlespeed 777'
         'examples': ['drillcncjob test.TXT -drillz -1.5 -travelz 14 -feedrate 222 -feedrate_rapid 456 -spindlespeed 777'
                      ' -toolchange True -toolchangez 33 -endz 22 -pp default\n'
                      ' -toolchange True -toolchangez 33 -endz 22 -pp default\n'
@@ -84,12 +85,20 @@ class TclCommandDrillcncjob(TclCommandSignaled):
         if 'outname' not in args:
         if 'outname' not in args:
             args['outname'] = name + "_cnc"
             args['outname'] = name + "_cnc"
 
 
+        if 'muted' in args:
+            muted = args['muted']
+        else:
+            muted = 0
+
         obj = self.app.collection.get_by_name(name)
         obj = self.app.collection.get_by_name(name)
         if obj is None:
         if obj is None:
             self.raise_tcl_error("Object not found: %s" % name)
             self.raise_tcl_error("Object not found: %s" % name)
 
 
         if not isinstance(obj, FlatCAMExcellon):
         if not isinstance(obj, FlatCAMExcellon):
-            self.raise_tcl_error('Expected FlatCAMExcellon, got %s %s.' % (name, type(obj)))
+            if not muted:
+                self.raise_tcl_error('Expected FlatCAMExcellon, got %s %s.' % (name, type(obj)))
+            else:
+                return
 
 
         xmin = obj.options['xmin']
         xmin = obj.options['xmin']
         ymin = obj.options['ymin']
         ymin = obj.options['ymin']
@@ -127,8 +136,11 @@ class TclCommandDrillcncjob(TclCommandSignaled):
                                     nr_diameters -= 1
                                     nr_diameters -= 1
 
 
                     if nr_diameters > 0:
                     if nr_diameters > 0:
-                        self.raise_tcl_error("One or more tool diameters of the drills to be drilled passed to the "
-                                             "TclCommand are not actual tool diameters in the Excellon object.")
+                        if not muted:
+                            self.raise_tcl_error("One or more tool diameters of the drills to be drilled passed to the "
+                                                 "TclCommand are not actual tool diameters in the Excellon object.")
+                        else:
+                            return
 
 
                     # make a string of diameters separated by comma; this is what generate_from_excellon_by_tool() is
                     # make a string of diameters separated by comma; this is what generate_from_excellon_by_tool() is
                     # expecting as tools parameter
                     # expecting as tools parameter
@@ -181,4 +193,4 @@ class TclCommandDrillcncjob(TclCommandSignaled):
             job_obj.gcode_parse()
             job_obj.gcode_parse()
             job_obj.create_geometry()
             job_obj.create_geometry()
 
 
-        self.app.new_object("cncjob", args['outname'], job_init)
+        self.app.new_object("cncjob", args['outname'], job_init, plot=False)

+ 1 - 1
tclCommands/TclCommandExteriors.py

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

+ 2 - 2
tclCommands/TclCommandGeoCutout.py

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

+ 1 - 1
tclCommands/TclCommandImportSvg.py

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

+ 1 - 1
tclCommands/TclCommandIsolate.py

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

+ 1 - 1
tclCommands/TclCommandJoinExcellon.py

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

+ 1 - 1
tclCommands/TclCommandJoinGeometry.py

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

+ 1 - 1
tclCommands/TclCommandMillDrills.py

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

+ 1 - 1
tclCommands/TclCommandMillSlots.py

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

+ 0 - 1
tclCommands/TclCommandMirror.py

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

+ 1 - 1
tclCommands/TclCommandNew.py

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

+ 51 - 0
tclCommands/TclCommandNewExcellon.py

@@ -0,0 +1,51 @@
+from ObjectCollection import *
+from tclCommands.TclCommand import TclCommandSignaled
+
+
+class TclCommandNewExcellon(TclCommandSignaled):
+    """
+    Tcl shell command to subtract polygon from the given Geometry object.
+    """
+
+    # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
+    aliases = ['new_excellon']
+
+    # Dictionary of types from Tcl command, needs to be ordered.
+    # For positional arguments
+    arg_names = collections.OrderedDict([
+        ('name', str)
+    ])
+
+    # Dictionary of types from Tcl command, needs to be ordered.
+    # For options like -optionname value
+    option_types = collections.OrderedDict([
+
+    ])
+
+    # array of mandatory options for current Tcl command: required = {'name','outname'}
+    required = []
+
+    # structured help for current command, args needs to be ordered
+    help = {
+        'main': "Creates a new empty Excellon object.",
+        'args': collections.OrderedDict([
+            ('name', 'New object name.'),
+        ]),
+        'examples': []
+    }
+
+    def execute(self, args, unnamed_args):
+        """
+        execute current TCL shell command
+
+        :param args: array of known named arguments and options
+        :param unnamed_args: array of other values which were passed into command
+            without -somename and  we do not have them in known arg_names
+        :return: None or exception
+        """
+
+        if 'name' in args:
+            name = args['name']
+        else:
+            name = 'new_exc'
+        self.app.new_object('excellon', name, lambda x, y: None, plot=False)

+ 6 - 4
tclCommands/TclCommandNewGeometry.py

@@ -23,7 +23,7 @@ class TclCommandNewGeometry(TclCommandSignaled):
     ])
     ])
 
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
     # array of mandatory options for current Tcl command: required = {'name','outname'}
-    required = ['name']
+    required = []
 
 
     # structured help for current command, args needs to be ordered
     # structured help for current command, args needs to be ordered
     help = {
     help = {
@@ -43,7 +43,9 @@ class TclCommandNewGeometry(TclCommandSignaled):
             without -somename and  we do not have them in known arg_names
             without -somename and  we do not have them in known arg_names
         :return: None or exception
         :return: None or exception
         """
         """
+        if 'name' in args:
+            name = args['name']
+        else:
+            name = 'new_geo'
 
 
-        name = args['name']
-
-        self.app.new_object('geometry', str(name), lambda x, y: None)
+        self.app.new_object('geometry', str(name), lambda x, y: None, plot=False)

+ 68 - 0
tclCommands/TclCommandNewGerber.py

@@ -0,0 +1,68 @@
+from ObjectCollection import *
+from tclCommands.TclCommand import TclCommandSignaled
+
+
+class TclCommandNewGerber(TclCommandSignaled):
+    """
+    Tcl shell command to subtract polygon from the given Geometry object.
+    """
+
+    # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
+    aliases = ['new_gerber']
+
+    # Dictionary of types from Tcl command, needs to be ordered.
+    # For positional arguments
+    arg_names = collections.OrderedDict([
+        ('name', str)
+    ])
+
+    # Dictionary of types from Tcl command, needs to be ordered.
+    # For options like -optionname value
+    option_types = collections.OrderedDict([
+
+    ])
+
+    # array of mandatory options for current Tcl command: required = {'name','outname'}
+    required = []
+
+    # structured help for current command, args needs to be ordered
+    help = {
+        'main': "Creates a new empty Gerber object.",
+        'args': collections.OrderedDict([
+            ('name', 'New object name.'),
+        ]),
+        'examples': []
+    }
+
+    def execute(self, args, unnamed_args):
+        """
+        execute current TCL shell command
+
+        :param args: array of known named arguments and options
+        :param unnamed_args: array of other values which were passed into command
+            without -somename and  we do not have them in known arg_names
+        :return: None or exception
+        """
+
+        if 'name' in args:
+            name = args['name']
+        else:
+            name = 'new_grb'
+
+        def initialize(grb_obj, self):
+            grb_obj.multitool = False
+            grb_obj.source_file = []
+            grb_obj.multigeo = False
+            grb_obj.follow = False
+            grb_obj.apertures = {}
+            grb_obj.solid_geometry = []
+
+            try:
+                grb_obj.options['xmin'] = 0
+                grb_obj.options['ymin'] = 0
+                grb_obj.options['xmax'] = 0
+                grb_obj.options['ymax'] = 0
+            except KeyError:
+                pass
+
+        self.app.new_object('gerber', name, initialize, plot=False)

+ 1 - 1
tclCommands/TclCommandNregions.py

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

+ 2 - 0
tclCommands/TclCommandOpenExcellon.py

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

+ 4 - 1
tclCommands/TclCommandOpenGCode.py

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

+ 5 - 12
tclCommands/TclCommandOpenGerber.py

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

+ 3 - 1
tclCommands/TclCommandOpenProject.py

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

+ 9 - 3
tclCommands/TclCommandPaint.py

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

+ 3 - 3
tclCommands/TclCommandPanelize.py

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

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

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

+ 51 - 0
tclCommands/TclCommandPlotObjects.py

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

+ 18 - 4
tclCommands/TclCommandWriteGCode.py

@@ -22,7 +22,8 @@ class TclCommandWriteGCode(TclCommandSignaled):
     # For options like -optionname value
     # For options like -optionname value
     option_types = collections.OrderedDict([
     option_types = collections.OrderedDict([
         ('preamble', str),
         ('preamble', str),
-        ('postamble', str)
+        ('postamble', str),
+        ('muted', int)
     ])
     ])
 
 
     # array of mandatory options for current Tcl command: required = {'name','outname'}
     # array of mandatory options for current Tcl command: required = {'name','outname'}
@@ -35,7 +36,9 @@ class TclCommandWriteGCode(TclCommandSignaled):
             ('name', 'Source CNC Job object.'),
             ('name', 'Source CNC Job object.'),
             ('filename', 'Output filename.'),
             ('filename', 'Output filename.'),
             ('preamble', 'Text to append at the beginning.'),
             ('preamble', 'Text to append at the beginning.'),
-            ('postamble', 'Text to append at the end.')
+            ('postamble', 'Text to append at the end.'),
+            ('muted', 'It will not put errors in the Shell or status bar.')
+
         ]),
         ]),
         'examples': ["write_gcode name c:\\\\gcode_repo"]
         'examples': ["write_gcode name c:\\\\gcode_repo"]
     }
     }
@@ -62,6 +65,11 @@ class TclCommandWriteGCode(TclCommandSignaled):
         preamble = args['preamble'] if 'preamble' in args else ''
         preamble = args['preamble'] if 'preamble' in args else ''
         postamble = args['postamble'] if 'postamble' in args else ''
         postamble = args['postamble'] if 'postamble' in args else ''
 
 
+        if 'muted' in args:
+            muted = args['muted']
+        else:
+            muted = 0
+
         # TODO: This is not needed any more? All targets should be present.
         # TODO: This is not needed any more? All targets should be present.
         # If there are promised objects, wait until all promises have been fulfilled.
         # If there are promised objects, wait until all promises have been fulfilled.
         # if self.collection.has_promises():
         # if self.collection.has_promises():
@@ -82,9 +90,15 @@ class TclCommandWriteGCode(TclCommandSignaled):
         try:
         try:
             obj = self.app.collection.get_by_name(str(obj_name))
             obj = self.app.collection.get_by_name(str(obj_name))
         except:
         except:
-            return "Could not retrieve object: %s" % obj_name
+            if not muted:
+                return "Could not retrieve object: %s" % obj_name
+            else:
+                return
 
 
         try:
         try:
             obj.export_gcode(str(filename), str(preamble), str(postamble))
             obj.export_gcode(str(filename), str(preamble), str(postamble))
         except Exception as e:
         except Exception as e:
-            return "Operation failed: %s" % str(e)
+            if not muted:
+                return "Operation failed: %s" % str(e)
+            else:
+                return

+ 4 - 1
tclCommands/__init__.py

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